From c1343b3278cdf99533b7902744d15969f9d6fdc1 Mon Sep 17 00:00:00 2001 From: Yves-Alexis Perez Date: Wed, 2 Jan 2013 14:18:20 +0100 Subject: Imported Upstream version 5.0.1 --- src/Makefile.am | 16 +- src/Makefile.in | 65 +- src/_copyright/Makefile.am | 3 +- src/_copyright/Makefile.in | 18 +- src/_copyright/_copyright.c | 36 +- src/_updown/Makefile.in | 12 +- src/_updown/_updown.in | 14 +- src/_updown_espmark/Makefile.in | 12 +- src/charon-nm/Makefile.am | 26 + src/charon-nm/Makefile.in | 676 +++ src/charon-nm/charon-nm.c | 269 + src/charon-nm/nm/nm_backend.c | 176 + src/charon-nm/nm/nm_backend.h | 36 + src/charon-nm/nm/nm_creds.c | 490 ++ src/charon-nm/nm/nm_creds.h | 102 + src/charon-nm/nm/nm_handler.c | 188 + src/charon-nm/nm/nm_handler.h | 62 + src/charon-nm/nm/nm_service.c | 720 +++ src/charon-nm/nm/nm_service.h | 55 + src/charon/Android.mk | 3 +- src/charon/Makefile.am | 5 +- src/charon/Makefile.in | 19 +- src/charon/charon.c | 103 +- src/checksum/Makefile.am | 10 +- src/checksum/Makefile.in | 60 +- src/checksum/checksum_builder.c | 6 +- src/conftest/Makefile.am | 3 +- src/conftest/Makefile.in | 18 +- src/conftest/config.c | 10 +- src/conftest/conftest.c | 11 +- src/conftest/hooks/add_notify.c | 8 +- src/conftest/hooks/add_payload.c | 6 +- src/conftest/hooks/custom_proposal.c | 9 +- src/conftest/hooks/force_cookie.c | 6 +- src/conftest/hooks/ignore_message.c | 4 +- src/conftest/hooks/ike_auth_fill.c | 11 +- src/conftest/hooks/log_id.c | 4 +- src/conftest/hooks/log_ke.c | 4 +- src/conftest/hooks/log_proposals.c | 4 +- src/conftest/hooks/log_ts.c | 4 +- src/conftest/hooks/pretend_auth.c | 66 +- src/conftest/hooks/rebuild_auth.c | 66 +- src/conftest/hooks/reset_seq.c | 3 - src/conftest/hooks/set_critical.c | 4 +- src/conftest/hooks/set_ike_initiator.c | 4 +- src/conftest/hooks/set_ike_request.c | 4 +- src/conftest/hooks/set_ike_spi.c | 4 +- src/conftest/hooks/set_ike_version.c | 4 +- src/conftest/hooks/set_length.c | 9 +- src/conftest/hooks/set_proposal_number.c | 6 +- src/conftest/hooks/set_reserved.c | 4 +- src/conftest/hooks/unencrypted_notify.c | 6 +- src/conftest/hooks/unsort_message.c | 4 +- src/dumm/Makefile.in | 14 +- src/dumm/ext/extconf.rb.in | 2 +- src/dumm/mconsole.c | 2 +- src/include/Makefile.in | 12 +- src/ipsec/Makefile.am | 25 +- src/ipsec/Makefile.in | 66 +- src/ipsec/_ipsec.8 | 291 + src/ipsec/_ipsec.8.in | 291 + src/ipsec/_ipsec.in | 335 ++ src/ipsec/ipsec.8 | 302 - src/ipsec/ipsec.8.in | 302 - src/ipsec/ipsec.in | 408 -- src/libcharon/Android.mk | 114 +- src/libcharon/Makefile.am | 159 +- src/libcharon/Makefile.in | 1213 ++-- src/libcharon/bus/bus.c | 380 +- src/libcharon/bus/bus.h | 75 +- src/libcharon/bus/listeners/file_logger.c | 116 +- src/libcharon/bus/listeners/file_logger.h | 6 +- src/libcharon/bus/listeners/listener.h | 44 +- src/libcharon/bus/listeners/logger.h | 63 + src/libcharon/bus/listeners/sys_logger.c | 85 +- src/libcharon/bus/listeners/sys_logger.h | 6 +- src/libcharon/config/backend_manager.c | 109 +- src/libcharon/config/backend_manager.h | 4 +- src/libcharon/config/child_cfg.c | 79 +- src/libcharon/config/child_cfg.h | 4 +- src/libcharon/config/ike_cfg.c | 29 +- src/libcharon/config/ike_cfg.h | 57 +- src/libcharon/config/peer_cfg.c | 155 +- src/libcharon/config/peer_cfg.h | 112 +- src/libcharon/config/proposal.c | 81 +- src/libcharon/config/proposal.h | 3 +- src/libcharon/control/controller.c | 437 +- src/libcharon/control/controller.h | 37 +- src/libcharon/daemon.c | 172 +- src/libcharon/daemon.h | 91 +- src/libcharon/encoding/generator.c | 154 +- src/libcharon/encoding/generator.h | 8 + src/libcharon/encoding/message.c | 770 ++- src/libcharon/encoding/message.h | 65 +- src/libcharon/encoding/parser.c | 232 +- src/libcharon/encoding/payloads/auth_payload.c | 23 +- src/libcharon/encoding/payloads/auth_payload.h | 7 +- src/libcharon/encoding/payloads/cert_payload.c | 58 +- src/libcharon/encoding/payloads/cert_payload.h | 27 +- src/libcharon/encoding/payloads/certreq_payload.c | 74 +- src/libcharon/encoding/payloads/certreq_payload.h | 34 +- .../encoding/payloads/configuration_attribute.c | 211 +- .../encoding/payloads/configuration_attribute.h | 44 +- src/libcharon/encoding/payloads/cp_payload.c | 144 +- src/libcharon/encoding/payloads/cp_payload.h | 35 +- src/libcharon/encoding/payloads/delete_payload.c | 143 +- src/libcharon/encoding/payloads/delete_payload.h | 21 +- src/libcharon/encoding/payloads/eap_payload.c | 189 +- src/libcharon/encoding/payloads/eap_payload.h | 29 +- src/libcharon/encoding/payloads/encodings.c | 20 +- src/libcharon/encoding/payloads/encodings.h | 199 +- .../encoding/payloads/encryption_payload.c | 177 +- .../encoding/payloads/encryption_payload.h | 16 +- src/libcharon/encoding/payloads/endpoint_notify.c | 2 +- src/libcharon/encoding/payloads/hash_payload.c | 177 + src/libcharon/encoding/payloads/hash_payload.h | 67 + src/libcharon/encoding/payloads/id_payload.c | 304 +- src/libcharon/encoding/payloads/id_payload.h | 48 +- src/libcharon/encoding/payloads/ike_header.c | 195 +- src/libcharon/encoding/payloads/ike_header.h | 139 +- src/libcharon/encoding/payloads/ke_payload.c | 76 +- src/libcharon/encoding/payloads/ke_payload.h | 32 +- src/libcharon/encoding/payloads/nonce_payload.c | 54 +- src/libcharon/encoding/payloads/nonce_payload.h | 14 +- src/libcharon/encoding/payloads/notify_payload.c | 284 +- src/libcharon/encoding/payloads/notify_payload.h | 62 +- src/libcharon/encoding/payloads/payload.c | 159 +- src/libcharon/encoding/payloads/payload.h | 175 +- .../encoding/payloads/proposal_substructure.c | 1218 +++- .../encoding/payloads/proposal_substructure.h | 120 +- src/libcharon/encoding/payloads/sa_payload.c | 366 +- src/libcharon/encoding/payloads/sa_payload.h | 94 +- .../payloads/traffic_selector_substructure.c | 22 +- .../payloads/traffic_selector_substructure.h | 5 - .../encoding/payloads/transform_attribute.c | 185 +- .../encoding/payloads/transform_attribute.h | 104 +- .../encoding/payloads/transform_substructure.c | 188 +- .../encoding/payloads/transform_substructure.h | 39 +- src/libcharon/encoding/payloads/ts_payload.c | 26 +- src/libcharon/encoding/payloads/ts_payload.h | 5 - src/libcharon/encoding/payloads/unknown_payload.c | 27 +- src/libcharon/encoding/payloads/unknown_payload.h | 5 - .../encoding/payloads/vendor_id_payload.c | 37 +- .../encoding/payloads/vendor_id_payload.h | 16 +- src/libcharon/kernel/kernel_handler.c | 2 +- src/libcharon/network/packet.c | 138 - src/libcharon/network/packet.h | 115 - src/libcharon/network/receiver.c | 297 +- src/libcharon/network/receiver.h | 42 +- src/libcharon/network/sender.c | 60 +- src/libcharon/network/sender.h | 19 +- src/libcharon/network/socket.h | 12 +- src/libcharon/network/socket_manager.c | 16 +- src/libcharon/network/socket_manager.h | 10 +- src/libcharon/plugins/addrblock/Makefile.in | 14 +- src/libcharon/plugins/android/Makefile.am | 1 - src/libcharon/plugins/android/Makefile.in | 19 +- src/libcharon/plugins/android/android_handler.c | 2 +- src/libcharon/plugins/android/android_logger.c | 97 - src/libcharon/plugins/android/android_logger.h | 52 - src/libcharon/plugins/android/android_plugin.c | 10 - src/libcharon/plugins/android/android_service.c | 36 +- src/libcharon/plugins/android_log/Makefile.am | 17 + src/libcharon/plugins/android_log/Makefile.in | 622 ++ .../plugins/android_log/android_log_logger.c | 108 + .../plugins/android_log/android_log_logger.h | 52 + .../plugins/android_log/android_log_plugin.c | 76 + .../plugins/android_log/android_log_plugin.h | 42 + src/libcharon/plugins/certexpire/Makefile.in | 14 +- .../plugins/certexpire/certexpire_export.c | 22 +- src/libcharon/plugins/coupling/Makefile.in | 14 +- .../plugins/coupling/coupling_validator.c | 37 +- src/libcharon/plugins/dhcp/Makefile.in | 14 +- src/libcharon/plugins/dhcp/dhcp_provider.c | 77 +- src/libcharon/plugins/dhcp/dhcp_socket.c | 43 +- src/libcharon/plugins/duplicheck/Makefile.in | 14 +- .../plugins/duplicheck/duplicheck_listener.c | 4 +- .../plugins/duplicheck/duplicheck_notify.c | 18 +- .../plugins/duplicheck/duplicheck_plugin.c | 2 +- src/libcharon/plugins/eap_aka/Makefile.in | 14 +- src/libcharon/plugins/eap_aka/eap_aka_peer.c | 160 +- src/libcharon/plugins/eap_aka/eap_aka_peer.h | 2 +- src/libcharon/plugins/eap_aka/eap_aka_server.c | 64 +- src/libcharon/plugins/eap_aka/eap_aka_server.h | 2 +- src/libcharon/plugins/eap_aka_3gpp2/Makefile.in | 14 +- .../plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c | 36 +- .../eap_aka_3gpp2/eap_aka_3gpp2_functions.c | 100 +- .../eap_aka_3gpp2/eap_aka_3gpp2_functions.h | 21 +- .../plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c | 35 +- src/libcharon/plugins/eap_dynamic/Makefile.am | 16 + src/libcharon/plugins/eap_dynamic/Makefile.in | 621 ++ src/libcharon/plugins/eap_dynamic/eap_dynamic.c | 393 ++ src/libcharon/plugins/eap_dynamic/eap_dynamic.h | 52 + .../plugins/eap_dynamic/eap_dynamic_plugin.c | 62 + .../plugins/eap_dynamic/eap_dynamic_plugin.h | 43 + src/libcharon/plugins/eap_gtc/Makefile.am | 2 +- src/libcharon/plugins/eap_gtc/Makefile.in | 16 +- src/libcharon/plugins/eap_gtc/eap_gtc.c | 130 +- src/libcharon/plugins/eap_gtc/eap_gtc.h | 2 +- src/libcharon/plugins/eap_gtc/eap_gtc_plugin.c | 11 - src/libcharon/plugins/eap_identity/Makefile.in | 14 +- src/libcharon/plugins/eap_identity/eap_identity.h | 2 +- src/libcharon/plugins/eap_md5/Makefile.in | 14 +- src/libcharon/plugins/eap_md5/eap_md5.c | 10 +- src/libcharon/plugins/eap_md5/eap_md5.h | 2 +- src/libcharon/plugins/eap_mschapv2/Makefile.in | 14 +- src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c | 116 +- src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h | 2 +- src/libcharon/plugins/eap_peap/Makefile.in | 14 +- src/libcharon/plugins/eap_peap/eap_peap.c | 13 +- src/libcharon/plugins/eap_peap/eap_peap.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap_peer.c | 5 +- src/libcharon/plugins/eap_peap/eap_peap_peer.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap_server.c | 26 +- src/libcharon/plugins/eap_peap/eap_peap_server.h | 2 +- src/libcharon/plugins/eap_radius/Makefile.in | 14 +- src/libcharon/plugins/eap_radius/eap_radius.c | 15 +- src/libcharon/plugins/eap_radius/eap_radius.h | 2 +- .../plugins/eap_radius/eap_radius_accounting.c | 48 +- src/libcharon/plugins/eap_radius/eap_radius_dae.c | 44 +- .../plugins/eap_radius/eap_radius_forward.c | 10 +- .../plugins/eap_radius/eap_radius_plugin.c | 44 +- src/libcharon/plugins/eap_sim/Makefile.in | 14 +- src/libcharon/plugins/eap_sim/eap_sim_peer.c | 161 +- src/libcharon/plugins/eap_sim/eap_sim_peer.h | 2 +- src/libcharon/plugins/eap_sim/eap_sim_server.c | 63 +- src/libcharon/plugins/eap_sim/eap_sim_server.h | 2 +- src/libcharon/plugins/eap_sim_file/Makefile.in | 14 +- src/libcharon/plugins/eap_sim_pcsc/Makefile.in | 14 +- .../plugins/eap_simaka_pseudonym/Makefile.in | 14 +- .../eap_simaka_pseudonym_provider.c | 11 +- .../plugins/eap_simaka_reauth/Makefile.in | 14 +- .../eap_simaka_reauth/eap_simaka_reauth_provider.c | 22 +- src/libcharon/plugins/eap_simaka_sql/Makefile.in | 14 +- .../plugins/eap_simaka_sql/eap_simaka_sql_plugin.c | 6 +- src/libcharon/plugins/eap_tls/Makefile.in | 14 +- src/libcharon/plugins/eap_tls/eap_tls.c | 8 +- src/libcharon/plugins/eap_tls/eap_tls.h | 2 +- src/libcharon/plugins/eap_tnc/Makefile.in | 14 +- src/libcharon/plugins/eap_tnc/eap_tnc.c | 37 +- src/libcharon/plugins/eap_tnc/eap_tnc.h | 4 +- src/libcharon/plugins/eap_ttls/Makefile.in | 14 +- src/libcharon/plugins/eap_ttls/eap_ttls.c | 13 +- src/libcharon/plugins/eap_ttls/eap_ttls.h | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 7 +- src/libcharon/plugins/eap_ttls/eap_ttls_server.c | 15 +- src/libcharon/plugins/farp/Makefile.in | 14 +- src/libcharon/plugins/farp/farp_spoofer.c | 12 +- src/libcharon/plugins/ha/Makefile.in | 14 +- src/libcharon/plugins/ha/ha_attribute.c | 42 +- src/libcharon/plugins/ha/ha_cache.c | 20 +- src/libcharon/plugins/ha/ha_ctl.c | 15 +- src/libcharon/plugins/ha/ha_dispatcher.c | 254 +- src/libcharon/plugins/ha/ha_ike.c | 160 +- src/libcharon/plugins/ha/ha_kernel.c | 3 +- src/libcharon/plugins/ha/ha_message.c | 20 +- src/libcharon/plugins/ha/ha_message.h | 16 +- src/libcharon/plugins/ha/ha_plugin.c | 14 +- src/libcharon/plugins/ha/ha_segments.c | 42 +- src/libcharon/plugins/ha/ha_socket.c | 1 + src/libcharon/plugins/ha/ha_tunnel.c | 11 +- src/libcharon/plugins/led/Makefile.in | 14 +- src/libcharon/plugins/led/led_listener.c | 9 +- src/libcharon/plugins/load_tester/Makefile.in | 14 +- .../plugins/load_tester/load_tester_config.c | 64 +- .../plugins/load_tester/load_tester_creds.c | 4 +- .../plugins/load_tester/load_tester_ipsec.c | 9 +- .../plugins/load_tester/load_tester_listener.c | 3 +- .../plugins/load_tester/load_tester_plugin.c | 119 +- src/libcharon/plugins/maemo/Makefile.in | 14 +- src/libcharon/plugins/maemo/maemo_service.c | 41 +- src/libcharon/plugins/medcli/Makefile.in | 14 +- src/libcharon/plugins/medcli/medcli_config.c | 26 +- src/libcharon/plugins/medsrv/Makefile.in | 14 +- src/libcharon/plugins/medsrv/medsrv_config.c | 9 +- src/libcharon/plugins/nm/Makefile.am | 21 - src/libcharon/plugins/nm/Makefile.in | 621 -- src/libcharon/plugins/nm/nm_creds.c | 490 -- src/libcharon/plugins/nm/nm_creds.h | 102 - src/libcharon/plugins/nm/nm_handler.c | 186 - src/libcharon/plugins/nm/nm_handler.h | 62 - src/libcharon/plugins/nm/nm_plugin.c | 142 - src/libcharon/plugins/nm/nm_plugin.h | 42 - src/libcharon/plugins/nm/nm_service.c | 704 --- src/libcharon/plugins/nm/nm_service.h | 55 - src/libcharon/plugins/radattr/Makefile.in | 14 +- src/libcharon/plugins/radattr/radattr_listener.c | 8 +- src/libcharon/plugins/smp/Makefile.in | 14 +- src/libcharon/plugins/smp/smp.c | 37 +- src/libcharon/plugins/socket_default/Makefile.in | 14 +- .../plugins/socket_default/socket_default_socket.c | 198 +- src/libcharon/plugins/socket_dynamic/Makefile.in | 14 +- .../plugins/socket_dynamic/socket_dynamic_socket.c | 65 +- src/libcharon/plugins/socket_raw/Makefile.am | 17 - src/libcharon/plugins/socket_raw/Makefile.in | 616 -- .../plugins/socket_raw/socket_raw_plugin.c | 79 - .../plugins/socket_raw/socket_raw_plugin.h | 42 - .../plugins/socket_raw/socket_raw_socket.c | 717 --- .../plugins/socket_raw/socket_raw_socket.h | 51 - src/libcharon/plugins/sql/Makefile.in | 14 +- src/libcharon/plugins/sql/sql_config.c | 23 +- src/libcharon/plugins/sql/sql_logger.c | 39 +- src/libcharon/plugins/sql/sql_logger.h | 4 +- src/libcharon/plugins/sql/sql_plugin.c | 7 +- src/libcharon/plugins/stroke/Makefile.am | 1 + src/libcharon/plugins/stroke/Makefile.in | 18 +- src/libcharon/plugins/stroke/stroke_attribute.c | 280 +- src/libcharon/plugins/stroke/stroke_attribute.h | 23 +- src/libcharon/plugins/stroke/stroke_ca.c | 10 +- src/libcharon/plugins/stroke/stroke_config.c | 473 +- src/libcharon/plugins/stroke/stroke_config.h | 4 +- src/libcharon/plugins/stroke/stroke_control.c | 85 +- src/libcharon/plugins/stroke/stroke_cred.c | 13 +- src/libcharon/plugins/stroke/stroke_handler.c | 231 + src/libcharon/plugins/stroke/stroke_handler.h | 64 + src/libcharon/plugins/stroke/stroke_list.c | 133 +- src/libcharon/plugins/stroke/stroke_plugin.c | 44 +- src/libcharon/plugins/stroke/stroke_socket.c | 60 +- src/libcharon/plugins/tnc_ifmap/Makefile.in | 14 +- .../plugins/tnc_ifmap/tnc_ifmap_listener.c | 6 +- src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap.c | 77 +- src/libcharon/plugins/tnc_imc/Makefile.am | 2 + src/libcharon/plugins/tnc_imc/Makefile.in | 16 +- src/libcharon/plugins/tnc_imc/tnc_imc_manager.c | 3 +- src/libcharon/plugins/tnc_imc/tnc_imc_plugin.c | 2 + src/libcharon/plugins/tnc_imv/Makefile.in | 14 +- src/libcharon/plugins/tnc_imv/tnc_imv_manager.c | 5 +- src/libcharon/plugins/tnc_imv/tnc_imv_plugin.c | 2 + .../plugins/tnc_imv/tnc_imv_recommendations.c | 58 +- src/libcharon/plugins/tnc_pdp/Makefile.in | 14 +- src/libcharon/plugins/tnc_pdp/tnc_pdp.c | 99 +- .../plugins/tnc_pdp/tnc_pdp_connections.c | 17 +- .../plugins/tnc_pdp/tnc_pdp_connections.h | 2 +- src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c | 4 +- src/libcharon/plugins/tnc_tnccs/Makefile.in | 14 +- .../plugins/tnc_tnccs/tnc_tnccs_manager.c | 20 +- src/libcharon/plugins/tnccs_11/Makefile.am | 2 + src/libcharon/plugins/tnccs_11/Makefile.in | 16 +- src/libcharon/plugins/tnccs_11/tnccs_11.c | 36 +- src/libcharon/plugins/tnccs_20/Makefile.am | 2 + src/libcharon/plugins/tnccs_20/Makefile.in | 16 +- .../plugins/tnccs_20/batch/pb_tnc_batch.c | 65 +- .../plugins/tnccs_20/batch/pb_tnc_batch.h | 10 +- .../messages/pb_access_recommendation_msg.c | 7 +- .../tnccs_20/messages/pb_assessment_result_msg.c | 7 +- .../plugins/tnccs_20/messages/pb_error_msg.c | 7 +- .../tnccs_20/messages/pb_language_preference_msg.c | 4 + .../plugins/tnccs_20/messages/pb_pa_msg.c | 41 +- .../plugins/tnccs_20/messages/pb_pa_msg.h | 7 +- .../tnccs_20/messages/pb_reason_string_msg.c | 7 +- .../messages/pb_remediation_parameters_msg.c | 6 +- .../tnccs_20/state_machine/pb_tnc_state_machine.c | 23 + .../tnccs_20/state_machine/pb_tnc_state_machine.h | 14 + src/libcharon/plugins/tnccs_20/tnccs_20.c | 226 +- src/libcharon/plugins/tnccs_dynamic/Makefile.in | 14 +- src/libcharon/plugins/uci/Makefile.in | 14 +- src/libcharon/plugins/uci/uci_config.c | 14 +- src/libcharon/plugins/uci/uci_control.c | 15 +- src/libcharon/plugins/unit_tester/Makefile.in | 14 +- .../plugins/unit_tester/tests/test_cert.c | 4 +- .../plugins/unit_tester/tests/test_pool.c | 11 +- src/libcharon/plugins/unity/Makefile.am | 19 + src/libcharon/plugins/unity/Makefile.in | 624 +++ src/libcharon/plugins/unity/unity_handler.c | 433 ++ src/libcharon/plugins/unity/unity_handler.h | 58 + src/libcharon/plugins/unity/unity_narrow.c | 171 + src/libcharon/plugins/unity/unity_narrow.h | 51 + src/libcharon/plugins/unity/unity_plugin.c | 96 + src/libcharon/plugins/unity/unity_plugin.h | 42 + src/libcharon/plugins/unity/unity_provider.c | 175 + src/libcharon/plugins/unity/unity_provider.h | 49 + src/libcharon/plugins/updown/Makefile.am | 1 + src/libcharon/plugins/updown/Makefile.in | 18 +- src/libcharon/plugins/updown/updown_handler.c | 243 + src/libcharon/plugins/updown/updown_handler.h | 57 + src/libcharon/plugins/updown/updown_listener.c | 117 +- src/libcharon/plugins/updown/updown_listener.h | 4 +- src/libcharon/plugins/updown/updown_plugin.c | 22 +- src/libcharon/plugins/whitelist/Makefile.in | 14 +- src/libcharon/plugins/whitelist/whitelist.c | 1 + .../plugins/whitelist/whitelist_control.c | 15 +- .../plugins/whitelist/whitelist_listener.c | 2 +- src/libcharon/plugins/xauth_eap/Makefile.am | 17 + src/libcharon/plugins/xauth_eap/Makefile.in | 622 ++ src/libcharon/plugins/xauth_eap/xauth_eap.c | 289 + src/libcharon/plugins/xauth_eap/xauth_eap.h | 55 + src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c | 60 + src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h | 42 + src/libcharon/plugins/xauth_generic/Makefile.am | 17 + src/libcharon/plugins/xauth_generic/Makefile.in | 622 ++ .../plugins/xauth_generic/xauth_generic.c | 232 + .../plugins/xauth_generic/xauth_generic.h | 60 + .../plugins/xauth_generic/xauth_generic_plugin.c | 62 + .../plugins/xauth_generic/xauth_generic_plugin.h | 42 + src/libcharon/plugins/xauth_pam/Makefile.am | 17 + src/libcharon/plugins/xauth_pam/Makefile.in | 622 ++ src/libcharon/plugins/xauth_pam/xauth_pam.c | 215 + src/libcharon/plugins/xauth_pam/xauth_pam.h | 49 + src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c | 67 + src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h | 42 + src/libcharon/processing/jobs/acquire_job.c | 4 +- src/libcharon/processing/jobs/adopt_children_job.c | 177 + src/libcharon/processing/jobs/adopt_children_job.h | 49 + .../processing/jobs/delete_child_sa_job.c | 15 +- .../processing/jobs/delete_child_sa_job.h | 4 +- src/libcharon/processing/jobs/delete_ike_sa_job.c | 6 +- src/libcharon/processing/jobs/dpd_timeout_job.c | 118 + src/libcharon/processing/jobs/dpd_timeout_job.h | 52 + src/libcharon/processing/jobs/inactivity_job.c | 15 +- .../processing/jobs/initiate_mediation_job.c | 25 +- src/libcharon/processing/jobs/mediation_job.c | 10 +- src/libcharon/processing/jobs/migrate_job.c | 21 +- .../processing/jobs/process_message_job.c | 7 +- src/libcharon/processing/jobs/rekey_child_sa_job.c | 4 +- src/libcharon/processing/jobs/rekey_ike_sa_job.c | 4 +- src/libcharon/processing/jobs/retransmit_job.c | 4 +- src/libcharon/processing/jobs/retry_initiate_job.c | 95 + src/libcharon/processing/jobs/retry_initiate_job.h | 48 + src/libcharon/processing/jobs/roam_job.c | 5 +- src/libcharon/processing/jobs/send_dpd_job.c | 4 +- src/libcharon/processing/jobs/send_keepalive_job.c | 4 +- src/libcharon/processing/jobs/start_action_job.c | 11 +- src/libcharon/processing/jobs/update_sa_job.c | 4 +- src/libcharon/sa/authenticator.c | 154 + src/libcharon/sa/authenticator.h | 223 + src/libcharon/sa/authenticators/authenticator.c | 98 - src/libcharon/sa/authenticators/authenticator.h | 166 - src/libcharon/sa/authenticators/eap/eap_manager.c | 162 - src/libcharon/sa/authenticators/eap/eap_manager.h | 82 - src/libcharon/sa/authenticators/eap/eap_method.c | 42 - src/libcharon/sa/authenticators/eap/eap_method.h | 177 - .../sa/authenticators/eap_authenticator.c | 698 --- .../sa/authenticators/eap_authenticator.h | 102 - .../sa/authenticators/psk_authenticator.c | 204 - .../sa/authenticators/psk_authenticator.h | 65 - .../sa/authenticators/pubkey_authenticator.c | 268 - .../sa/authenticators/pubkey_authenticator.h | 66 - src/libcharon/sa/child_sa.c | 79 +- src/libcharon/sa/child_sa.h | 12 +- src/libcharon/sa/connect_manager.c | 1600 ------ src/libcharon/sa/connect_manager.h | 126 - src/libcharon/sa/eap/eap_manager.c | 201 + src/libcharon/sa/eap/eap_manager.h | 94 + src/libcharon/sa/eap/eap_method.c | 42 + src/libcharon/sa/eap/eap_method.h | 177 + src/libcharon/sa/ike_sa.c | 694 ++- src/libcharon/sa/ike_sa.h | 102 +- src/libcharon/sa/ike_sa_id.c | 51 +- src/libcharon/sa/ike_sa_id.h | 31 +- src/libcharon/sa/ike_sa_manager.c | 914 +-- src/libcharon/sa/ike_sa_manager.h | 18 +- .../sa/ikev1/authenticators/hybrid_authenticator.c | 114 + .../sa/ikev1/authenticators/hybrid_authenticator.h | 56 + .../sa/ikev1/authenticators/psk_v1_authenticator.c | 172 + .../sa/ikev1/authenticators/psk_v1_authenticator.h | 57 + .../ikev1/authenticators/pubkey_v1_authenticator.c | 233 + .../ikev1/authenticators/pubkey_v1_authenticator.h | 57 + src/libcharon/sa/ikev1/keymat_v1.c | 1157 ++++ src/libcharon/sa/ikev1/keymat_v1.h | 166 + src/libcharon/sa/ikev1/phase1.c | 795 +++ src/libcharon/sa/ikev1/phase1.h | 166 + src/libcharon/sa/ikev1/task_manager_v1.c | 1714 ++++++ src/libcharon/sa/ikev1/task_manager_v1.h | 46 + src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 714 +++ src/libcharon/sa/ikev1/tasks/aggressive_mode.h | 50 + src/libcharon/sa/ikev1/tasks/informational.c | 253 + src/libcharon/sa/ikev1/tasks/informational.h | 51 + src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c | 359 ++ src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h | 53 + src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c | 578 ++ src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h | 53 + src/libcharon/sa/ikev1/tasks/isakmp_delete.c | 147 + src/libcharon/sa/ikev1/tasks/isakmp_delete.h | 50 + src/libcharon/sa/ikev1/tasks/isakmp_dpd.c | 123 + src/libcharon/sa/ikev1/tasks/isakmp_dpd.h | 52 + src/libcharon/sa/ikev1/tasks/isakmp_natd.c | 456 ++ src/libcharon/sa/ikev1/tasks/isakmp_natd.h | 50 + src/libcharon/sa/ikev1/tasks/isakmp_vendor.c | 225 + src/libcharon/sa/ikev1/tasks/isakmp_vendor.h | 49 + src/libcharon/sa/ikev1/tasks/main_mode.c | 735 +++ src/libcharon/sa/ikev1/tasks/main_mode.h | 50 + src/libcharon/sa/ikev1/tasks/mode_config.c | 459 ++ src/libcharon/sa/ikev1/tasks/mode_config.h | 50 + src/libcharon/sa/ikev1/tasks/quick_delete.c | 247 + src/libcharon/sa/ikev1/tasks/quick_delete.h | 55 + src/libcharon/sa/ikev1/tasks/quick_mode.c | 1273 +++++ src/libcharon/sa/ikev1/tasks/quick_mode.h | 67 + src/libcharon/sa/ikev1/tasks/xauth.c | 551 ++ src/libcharon/sa/ikev1/tasks/xauth.h | 50 + .../sa/ikev2/authenticators/eap_authenticator.c | 743 +++ .../sa/ikev2/authenticators/eap_authenticator.h | 102 + .../sa/ikev2/authenticators/psk_authenticator.c | 211 + .../sa/ikev2/authenticators/psk_authenticator.h | 65 + .../sa/ikev2/authenticators/pubkey_authenticator.c | 272 + .../sa/ikev2/authenticators/pubkey_authenticator.h | 66 + src/libcharon/sa/ikev2/connect_manager.c | 1615 ++++++ src/libcharon/sa/ikev2/connect_manager.h | 126 + src/libcharon/sa/ikev2/keymat_v2.c | 687 +++ src/libcharon/sa/ikev2/keymat_v2.h | 137 + src/libcharon/sa/ikev2/mediation_manager.c | 332 ++ src/libcharon/sa/ikev2/mediation_manager.h | 90 + src/libcharon/sa/ikev2/task_manager_v2.c | 1502 +++++ src/libcharon/sa/ikev2/task_manager_v2.h | 46 + src/libcharon/sa/ikev2/tasks/child_create.c | 1426 +++++ src/libcharon/sa/ikev2/tasks/child_create.h | 90 + src/libcharon/sa/ikev2/tasks/child_delete.c | 410 ++ src/libcharon/sa/ikev2/tasks/child_delete.h | 61 + src/libcharon/sa/ikev2/tasks/child_rekey.c | 485 ++ src/libcharon/sa/ikev2/tasks/child_rekey.h | 64 + src/libcharon/sa/ikev2/tasks/ike_auth.c | 1110 ++++ src/libcharon/sa/ikev2/tasks/ike_auth.h | 57 + src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c | 172 + src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h | 53 + src/libcharon/sa/ikev2/tasks/ike_cert_post.c | 261 + src/libcharon/sa/ikev2/tasks/ike_cert_post.h | 53 + src/libcharon/sa/ikev2/tasks/ike_cert_pre.c | 529 ++ src/libcharon/sa/ikev2/tasks/ike_cert_pre.h | 53 + src/libcharon/sa/ikev2/tasks/ike_config.c | 510 ++ src/libcharon/sa/ikev2/tasks/ike_config.h | 51 + src/libcharon/sa/ikev2/tasks/ike_delete.c | 199 + src/libcharon/sa/ikev2/tasks/ike_delete.h | 50 + src/libcharon/sa/ikev2/tasks/ike_dpd.c | 94 + src/libcharon/sa/ikev2/tasks/ike_dpd.h | 51 + src/libcharon/sa/ikev2/tasks/ike_init.c | 600 ++ src/libcharon/sa/ikev2/tasks/ike_init.h | 60 + src/libcharon/sa/ikev2/tasks/ike_me.c | 845 +++ src/libcharon/sa/ikev2/tasks/ike_me.h | 100 + src/libcharon/sa/ikev2/tasks/ike_mobike.c | 670 +++ src/libcharon/sa/ikev2/tasks/ike_mobike.h | 93 + src/libcharon/sa/ikev2/tasks/ike_natd.c | 472 ++ src/libcharon/sa/ikev2/tasks/ike_natd.h | 59 + src/libcharon/sa/ikev2/tasks/ike_reauth.c | 110 + src/libcharon/sa/ikev2/tasks/ike_reauth.h | 51 + src/libcharon/sa/ikev2/tasks/ike_rekey.c | 412 ++ src/libcharon/sa/ikev2/tasks/ike_rekey.h | 61 + src/libcharon/sa/ikev2/tasks/ike_vendor.c | 141 + src/libcharon/sa/ikev2/tasks/ike_vendor.h | 49 + src/libcharon/sa/keymat.c | 653 +-- src/libcharon/sa/keymat.h | 141 +- src/libcharon/sa/mediation_manager.c | 332 -- src/libcharon/sa/mediation_manager.h | 90 - src/libcharon/sa/shunt_manager.c | 1 + src/libcharon/sa/task.c | 52 + src/libcharon/sa/task.h | 178 + src/libcharon/sa/task_manager.c | 1139 +--- src/libcharon/sa/task_manager.h | 83 +- src/libcharon/sa/tasks/child_create.c | 1330 ----- src/libcharon/sa/tasks/child_create.h | 83 - src/libcharon/sa/tasks/child_delete.c | 391 -- src/libcharon/sa/tasks/child_delete.h | 60 - src/libcharon/sa/tasks/child_rekey.c | 482 -- src/libcharon/sa/tasks/child_rekey.h | 64 - src/libcharon/sa/tasks/ike_auth.c | 1107 ---- src/libcharon/sa/tasks/ike_auth.h | 57 - src/libcharon/sa/tasks/ike_auth_lifetime.c | 173 - src/libcharon/sa/tasks/ike_auth_lifetime.h | 53 - src/libcharon/sa/tasks/ike_cert_post.c | 257 - src/libcharon/sa/tasks/ike_cert_post.h | 53 - src/libcharon/sa/tasks/ike_cert_pre.c | 528 -- src/libcharon/sa/tasks/ike_cert_pre.h | 53 - src/libcharon/sa/tasks/ike_config.c | 443 -- src/libcharon/sa/tasks/ike_config.h | 51 - src/libcharon/sa/tasks/ike_delete.c | 199 - src/libcharon/sa/tasks/ike_delete.h | 50 - src/libcharon/sa/tasks/ike_dpd.c | 94 - src/libcharon/sa/tasks/ike_dpd.h | 51 - src/libcharon/sa/tasks/ike_init.c | 587 -- src/libcharon/sa/tasks/ike_init.h | 60 - src/libcharon/sa/tasks/ike_me.c | 833 --- src/libcharon/sa/tasks/ike_me.h | 100 - src/libcharon/sa/tasks/ike_mobike.c | 649 --- src/libcharon/sa/tasks/ike_mobike.h | 93 - src/libcharon/sa/tasks/ike_natd.c | 448 -- src/libcharon/sa/tasks/ike_natd.h | 59 - src/libcharon/sa/tasks/ike_reauth.c | 111 - src/libcharon/sa/tasks/ike_reauth.h | 51 - src/libcharon/sa/tasks/ike_rekey.c | 403 -- src/libcharon/sa/tasks/ike_rekey.h | 61 - src/libcharon/sa/tasks/ike_vendor.c | 141 - src/libcharon/sa/tasks/ike_vendor.h | 49 - src/libcharon/sa/tasks/task.c | 58 - src/libcharon/sa/tasks/task.h | 150 - src/libcharon/sa/trap_manager.c | 60 +- src/libcharon/sa/xauth/xauth_manager.c | 157 + src/libcharon/sa/xauth/xauth_manager.h | 79 + src/libcharon/sa/xauth/xauth_method.c | 42 + src/libcharon/sa/xauth/xauth_method.h | 126 + src/libfast/Makefile.am | 11 +- src/libfast/Makefile.in | 75 +- src/libfast/dispatcher.c | 14 +- src/libfast/request.c | 60 + src/libfast/request.h | 9 + src/libfast/session.c | 20 +- src/libfast/session.h | 1 + src/libfast/smtp.c | 11 +- src/libfreeswan/Android.mk | 38 - src/libfreeswan/Makefile.am | 22 - src/libfreeswan/Makefile.in | 682 --- src/libfreeswan/addrtoa.c | 66 - src/libfreeswan/addrtot.c | 302 - src/libfreeswan/addrtypeof.c | 94 - src/libfreeswan/anyaddr.3 | 86 - src/libfreeswan/anyaddr.c | 147 - src/libfreeswan/atoaddr.3 | 291 - src/libfreeswan/atoaddr.c | 261 - src/libfreeswan/atoasr.3 | 185 - src/libfreeswan/atoasr.c | 210 - src/libfreeswan/atosubnet.c | 214 - src/libfreeswan/atoul.3 | 160 - src/libfreeswan/atoul.c | 88 - src/libfreeswan/copyright.c | 57 - src/libfreeswan/datatot.c | 230 - src/libfreeswan/freeswan.h | 371 -- src/libfreeswan/goodmask.3 | 56 - src/libfreeswan/goodmask.c | 95 - src/libfreeswan/initaddr.3 | 128 - src/libfreeswan/initaddr.c | 51 - src/libfreeswan/initsaid.c | 31 - src/libfreeswan/initsubnet.3 | 136 - src/libfreeswan/initsubnet.c | 93 - src/libfreeswan/internal.h | 46 - src/libfreeswan/ipsec_param.h | 54 - src/libfreeswan/pfkey.h | 205 - src/libfreeswan/pfkey_v2_build.c | 1388 ----- src/libfreeswan/pfkey_v2_debug.c | 104 - src/libfreeswan/pfkey_v2_ext_bits.c | 692 --- src/libfreeswan/pfkey_v2_parse.c | 1539 ----- src/libfreeswan/pfkeyv2.h | 368 -- src/libfreeswan/portof.3 | 69 - src/libfreeswan/portof.c | 96 - src/libfreeswan/rangetoa.c | 59 - src/libfreeswan/rangetosubnet.3 | 58 - src/libfreeswan/rangetosubnet.c | 224 - src/libfreeswan/sameaddr.3 | 164 - src/libfreeswan/sameaddr.c | 188 - src/libfreeswan/satot.c | 132 - src/libfreeswan/subnetof.3 | 46 - src/libfreeswan/subnetof.c | 58 - src/libfreeswan/subnettoa.c | 60 - src/libfreeswan/subnettot.c | 54 - src/libfreeswan/subnettypeof.c | 107 - src/libfreeswan/ttoaddr.3 | 374 -- src/libfreeswan/ttoaddr.c | 471 -- src/libfreeswan/ttodata.3 | 280 - src/libfreeswan/ttodata.c | 720 --- src/libfreeswan/ttoprotoport.c | 101 - src/libfreeswan/ttosa.3 | 287 - src/libfreeswan/ttosa.c | 280 - src/libfreeswan/ttosubnet.c | 296 - src/libfreeswan/ttoul.3 | 191 - src/libfreeswan/ttoul.c | 89 - src/libfreeswan/ultoa.c | 65 - src/libfreeswan/ultot.c | 81 - src/libhydra/Makefile.in | 14 +- src/libhydra/attributes/attribute_handler.h | 6 +- src/libhydra/attributes/attribute_manager.c | 75 +- src/libhydra/attributes/attribute_manager.h | 23 +- src/libhydra/attributes/attribute_provider.h | 17 +- src/libhydra/attributes/mem_pool.c | 208 +- src/libhydra/attributes/mem_pool.h | 28 +- src/libhydra/hydra.c | 3 +- src/libhydra/kernel/kernel_interface.c | 223 +- src/libhydra/kernel/kernel_interface.h | 105 +- src/libhydra/kernel/kernel_ipsec.c | 22 - src/libhydra/kernel/kernel_ipsec.h | 153 +- src/libhydra/kernel/kernel_net.h | 43 +- src/libhydra/plugins/attr/Makefile.in | 14 +- src/libhydra/plugins/attr/attr_provider.c | 74 +- src/libhydra/plugins/attr_sql/Makefile.in | 14 +- src/libhydra/plugins/attr_sql/pool_attributes.c | 6 +- src/libhydra/plugins/attr_sql/sql_attribute.c | 97 +- src/libhydra/plugins/kernel_klips/Makefile.in | 14 +- .../plugins/kernel_klips/kernel_klips_ipsec.c | 65 +- src/libhydra/plugins/kernel_netlink/Makefile.in | 14 +- .../plugins/kernel_netlink/kernel_netlink_ipsec.c | 353 +- .../plugins/kernel_netlink/kernel_netlink_net.c | 1712 ++++-- .../plugins/kernel_netlink/kernel_netlink_shared.c | 5 + src/libhydra/plugins/kernel_pfkey/Makefile.in | 14 +- .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 205 +- src/libhydra/plugins/kernel_pfroute/Makefile.in | 14 +- .../plugins/kernel_pfroute/kernel_pfroute_net.c | 325 +- src/libhydra/plugins/resolve/Makefile.in | 14 +- src/libhydra/plugins/resolve/resolve_handler.c | 83 +- src/libimcv/Makefile.am | 3 + src/libimcv/Makefile.in | 46 +- src/libimcv/ietf/ietf_attr.c | 12 +- src/libimcv/ietf/ietf_attr_assess_result.c | 209 + src/libimcv/ietf/ietf_attr_assess_result.h | 63 + src/libimcv/ietf/ietf_attr_attr_request.c | 270 + src/libimcv/ietf/ietf_attr_attr_request.h | 71 + src/libimcv/ietf/ietf_attr_pa_tnc_error.c | 82 +- src/libimcv/ietf/ietf_attr_pa_tnc_error.h | 18 +- src/libimcv/ietf/ietf_attr_port_filter.c | 29 +- src/libimcv/ietf/ietf_attr_product_info.c | 29 +- src/libimcv/imc/imc_agent.c | 170 +- src/libimcv/imc/imc_agent.h | 8 +- src/libimcv/imc/imc_state.h | 41 +- src/libimcv/imcv.c | 2 +- src/libimcv/imv/imv_agent.c | 210 +- src/libimcv/imv/imv_agent.h | 12 +- src/libimcv/imv/imv_state.h | 17 +- src/libimcv/ita/ita_attr.c | 8 +- src/libimcv/ita/ita_attr.h | 3 +- src/libimcv/ita/ita_attr_command.c | 32 +- src/libimcv/ita/ita_attr_dummy.c | 183 + src/libimcv/ita/ita_attr_dummy.h | 61 + src/libimcv/pa_tnc/pa_tnc_attr.h | 15 +- src/libimcv/pa_tnc/pa_tnc_msg.c | 165 +- src/libimcv/pa_tnc/pa_tnc_msg.h | 11 +- src/libimcv/plugins/imc_scanner/Makefile.in | 14 +- src/libimcv/plugins/imc_scanner/imc_scanner.c | 67 +- .../plugins/imc_scanner/imc_scanner_state.c | 51 +- src/libimcv/plugins/imc_test/Makefile.in | 14 +- src/libimcv/plugins/imc_test/imc_test.c | 103 +- src/libimcv/plugins/imc_test/imc_test_state.c | 117 +- src/libimcv/plugins/imc_test/imc_test_state.h | 16 +- src/libimcv/plugins/imv_scanner/Makefile.in | 14 +- src/libimcv/plugins/imv_scanner/imv_scanner.c | 17 +- .../plugins/imv_scanner/imv_scanner_state.c | 22 +- src/libimcv/plugins/imv_test/Makefile.in | 14 +- src/libimcv/plugins/imv_test/imv_test.c | 46 +- src/libimcv/plugins/imv_test/imv_test_state.c | 22 +- src/libipsec/Android.mk | 38 + src/libipsec/Makefile.am | 31 + src/libipsec/Makefile.in | 780 +++ src/libipsec/esp_context.c | 301 + src/libipsec/esp_context.h | 110 + src/libipsec/esp_packet.c | 468 ++ src/libipsec/esp_packet.h | 151 + src/libipsec/ip_packet.c | 193 + src/libipsec/ip_packet.h | 96 + src/libipsec/ipsec.c | 77 + src/libipsec/ipsec.h | 83 + src/libipsec/ipsec_event_listener.h | 48 + src/libipsec/ipsec_event_relay.c | 193 + src/libipsec/ipsec_event_relay.h | 79 + src/libipsec/ipsec_policy.c | 212 + src/libipsec/ipsec_policy.h | 140 + src/libipsec/ipsec_policy_mgr.c | 286 + src/libipsec/ipsec_policy_mgr.h | 119 + src/libipsec/ipsec_processor.c | 324 ++ src/libipsec/ipsec_processor.h | 115 + src/libipsec/ipsec_sa.c | 234 + src/libipsec/ipsec_sa.h | 169 + src/libipsec/ipsec_sa_mgr.c | 626 +++ src/libipsec/ipsec_sa_mgr.h | 167 + src/libpts/Makefile.am | 1 + src/libpts/Makefile.in | 27 +- src/libpts/plugins/imc_attestation/Makefile.in | 14 +- .../plugins/imc_attestation/imc_attestation.c | 88 +- .../imc_attestation/imc_attestation_process.c | 72 +- .../imc_attestation/imc_attestation_state.c | 103 +- .../imc_attestation/imc_attestation_state.h | 19 +- src/libpts/plugins/imv_attestation/Makefile.am | 2 + src/libpts/plugins/imv_attestation/Makefile.in | 15 +- src/libpts/plugins/imv_attestation/attest.c | 18 +- src/libpts/plugins/imv_attestation/attest_db.c | 382 +- src/libpts/plugins/imv_attestation/attest_db.h | 15 + src/libpts/plugins/imv_attestation/attest_usage.c | 23 +- .../plugins/imv_attestation/build-database.sh | 221 + src/libpts/plugins/imv_attestation/data.sql | 371 +- .../plugins/imv_attestation/imv_attestation.c | 74 +- .../imv_attestation/imv_attestation_build.c | 24 +- .../imv_attestation/imv_attestation_process.c | 72 +- .../imv_attestation/imv_attestation_state.c | 162 +- .../imv_attestation/imv_attestation_state.h | 36 +- src/libpts/plugins/imv_attestation/tables.sql | 5 + src/libpts/pts/components/ita/ita_comp_ima.c | 807 ++- src/libpts/pts/components/ita/ita_comp_ima.h | 5 +- src/libpts/pts/components/ita/ita_comp_tboot.c | 149 +- src/libpts/pts/components/ita/ita_comp_tboot.h | 5 +- src/libpts/pts/components/ita/ita_comp_tgrub.c | 65 +- src/libpts/pts/components/ita/ita_comp_tgrub.h | 5 +- src/libpts/pts/components/pts_comp_evidence.c | 22 +- src/libpts/pts/components/pts_comp_evidence.h | 4 +- src/libpts/pts/components/pts_comp_func_name.c | 9 +- src/libpts/pts/components/pts_comp_func_name.h | 9 +- src/libpts/pts/components/pts_component.h | 24 +- src/libpts/pts/components/pts_component_manager.c | 6 +- src/libpts/pts/components/pts_component_manager.h | 3 +- src/libpts/pts/pts.c | 420 +- src/libpts/pts/pts.h | 53 +- src/libpts/pts/pts_database.c | 41 +- src/libpts/pts/pts_database.h | 13 + src/libpts/pts/pts_error.c | 12 +- src/libpts/pts/pts_file_meas.c | 188 + src/libpts/pts/pts_file_meas.h | 26 + src/libpts/pts/pts_meas_algo.c | 21 +- src/libpts/pts/pts_meas_algo.h | 9 +- src/libpts/pts/pts_pcr.c | 289 + src/libpts/pts/pts_pcr.h | 118 + src/libpts/tcg/tcg_pts_attr_aik.c | 31 +- src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c | 31 +- src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c | 31 +- src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c | 31 +- src/libpts/tcg/tcg_pts_attr_file_meas.c | 31 +- src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c | 31 +- src/libpts/tcg/tcg_pts_attr_get_aik.c | 31 +- src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c | 31 +- src/libpts/tcg/tcg_pts_attr_meas_algo.c | 33 +- src/libpts/tcg/tcg_pts_attr_proto_caps.c | 33 +- src/libpts/tcg/tcg_pts_attr_req_file_meas.c | 31 +- src/libpts/tcg/tcg_pts_attr_req_file_meta.c | 31 +- src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c | 31 +- src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c | 51 +- src/libpts/tcg/tcg_pts_attr_simple_evid_final.c | 31 +- src/libpts/tcg/tcg_pts_attr_tpm_version_info.c | 31 +- src/libpts/tcg/tcg_pts_attr_unix_file_meta.c | 31 +- src/libradius/Makefile.in | 14 +- src/libradius/radius_message.c | 28 +- src/libradius/radius_message.h | 3 +- src/libradius/radius_socket.c | 18 +- src/libsimaka/Makefile.in | 14 +- src/libsimaka/simaka_crypto.c | 94 +- src/libsimaka/simaka_crypto.h | 18 +- src/libsimaka/simaka_message.c | 28 +- src/libsimaka/simaka_message.h | 5 +- src/libstrongswan/Android.mk | 108 +- src/libstrongswan/AndroidConfigLocal.h | 15 + src/libstrongswan/Makefile.am | 167 +- src/libstrongswan/Makefile.in | 759 ++- src/libstrongswan/asn1/asn1.c | 20 +- src/libstrongswan/asn1/oid.c | 289 +- src/libstrongswan/asn1/oid.h | 141 +- src/libstrongswan/asn1/oid.txt | 3 + src/libstrongswan/bio/bio_reader.c | 174 +- src/libstrongswan/bio/bio_reader.h | 54 + src/libstrongswan/bio/bio_writer.c | 28 + src/libstrongswan/bio/bio_writer.h | 25 + src/libstrongswan/chunk.c | 8 +- src/libstrongswan/chunk.h | 11 +- src/libstrongswan/credentials/auth_cfg.c | 210 +- src/libstrongswan/credentials/auth_cfg.h | 13 +- .../credentials/certificates/certificate.h | 4 +- src/libstrongswan/credentials/certificates/x509.h | 2 + src/libstrongswan/credentials/credential_manager.c | 200 +- src/libstrongswan/credentials/credential_manager.h | 12 +- src/libstrongswan/credentials/sets/cert_cache.c | 28 +- src/libstrongswan/credentials/sets/cert_cache.h | 4 +- src/libstrongswan/crypto/aead.c | 45 +- src/libstrongswan/crypto/aead.h | 9 +- src/libstrongswan/crypto/crypters/crypter.h | 20 +- src/libstrongswan/crypto/crypto_factory.c | 104 +- src/libstrongswan/crypto/crypto_factory.h | 51 +- src/libstrongswan/crypto/crypto_tester.c | 371 +- src/libstrongswan/crypto/hashers/hasher.c | 116 +- src/libstrongswan/crypto/hashers/hasher.h | 53 +- src/libstrongswan/crypto/mac.h | 76 + src/libstrongswan/crypto/nonce_gen.h | 59 + src/libstrongswan/crypto/pkcs7.c | 1061 ++++ src/libstrongswan/crypto/pkcs7.h | 178 + src/libstrongswan/crypto/pkcs9.c | 101 +- src/libstrongswan/crypto/pkcs9.h | 19 +- src/libstrongswan/crypto/prf_plus.c | 126 +- src/libstrongswan/crypto/prf_plus.h | 34 +- src/libstrongswan/crypto/prfs/mac_prf.c | 101 + src/libstrongswan/crypto/prfs/mac_prf.h | 36 + src/libstrongswan/crypto/prfs/prf.h | 19 +- .../crypto/proposal/proposal_keywords.c | 416 +- .../crypto/proposal/proposal_keywords.h | 109 +- .../crypto/proposal/proposal_keywords.txt | 153 - .../crypto/proposal/proposal_keywords_static.c | 324 ++ .../crypto/proposal/proposal_keywords_static.h | 25 + .../crypto/proposal/proposal_keywords_static.txt | 153 + src/libstrongswan/crypto/rngs/rng.c | 41 + src/libstrongswan/crypto/rngs/rng.h | 39 +- src/libstrongswan/crypto/signers/mac_signer.c | 139 + src/libstrongswan/crypto/signers/mac_signer.h | 41 + src/libstrongswan/crypto/signers/signer.h | 20 +- src/libstrongswan/crypto/transform.c | 7 +- src/libstrongswan/crypto/transform.h | 3 +- src/libstrongswan/debug.c | 4 + src/libstrongswan/debug.h | 4 + src/libstrongswan/eap/eap.c | 80 +- src/libstrongswan/eap/eap.h | 39 +- src/libstrongswan/enum.c | 6 +- src/libstrongswan/enum.h | 2 +- src/libstrongswan/ipsec/ipsec_types.c | 38 + src/libstrongswan/ipsec/ipsec_types.h | 172 + src/libstrongswan/library.c | 6 + src/libstrongswan/library.h | 13 + src/libstrongswan/pen/pen.c | 8 +- src/libstrongswan/pen/pen.h | 22 +- src/libstrongswan/plugins/aes/Makefile.in | 14 +- src/libstrongswan/plugins/aes/aes_crypter.c | 9 +- src/libstrongswan/plugins/af_alg/Makefile.in | 14 +- src/libstrongswan/plugins/af_alg/af_alg_crypter.c | 22 +- src/libstrongswan/plugins/af_alg/af_alg_hasher.c | 16 +- src/libstrongswan/plugins/af_alg/af_alg_ops.c | 73 +- src/libstrongswan/plugins/af_alg/af_alg_ops.h | 9 +- src/libstrongswan/plugins/af_alg/af_alg_prf.c | 24 +- src/libstrongswan/plugins/af_alg/af_alg_signer.c | 22 +- src/libstrongswan/plugins/agent/Makefile.in | 14 +- src/libstrongswan/plugins/blowfish/Makefile.in | 14 +- .../plugins/blowfish/blowfish_crypter.c | 11 +- src/libstrongswan/plugins/ccm/Makefile.in | 14 +- src/libstrongswan/plugins/ccm/ccm_aead.c | 70 +- src/libstrongswan/plugins/cmac/Makefile.am | 3 +- src/libstrongswan/plugins/cmac/Makefile.in | 22 +- src/libstrongswan/plugins/cmac/cmac.c | 127 +- src/libstrongswan/plugins/cmac/cmac.h | 60 +- src/libstrongswan/plugins/cmac/cmac_plugin.c | 3 +- src/libstrongswan/plugins/cmac/cmac_prf.c | 121 - src/libstrongswan/plugins/cmac/cmac_prf.h | 50 - src/libstrongswan/plugins/cmac/cmac_signer.c | 159 - src/libstrongswan/plugins/cmac/cmac_signer.h | 47 - src/libstrongswan/plugins/constraints/Makefile.in | 14 +- src/libstrongswan/plugins/ctr/Makefile.in | 14 +- src/libstrongswan/plugins/ctr/ctr_ipsec_crypter.c | 23 +- src/libstrongswan/plugins/curl/Makefile.in | 14 +- src/libstrongswan/plugins/des/Makefile.in | 14 +- src/libstrongswan/plugins/des/des_crypter.c | 24 +- src/libstrongswan/plugins/dnskey/Makefile.in | 14 +- src/libstrongswan/plugins/fips_prf/Makefile.in | 14 +- src/libstrongswan/plugins/fips_prf/fips_prf.c | 23 +- src/libstrongswan/plugins/gcm/Makefile.in | 14 +- src/libstrongswan/plugins/gcm/gcm_aead.c | 65 +- src/libstrongswan/plugins/gcrypt/Makefile.in | 14 +- src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c | 45 +- src/libstrongswan/plugins/gcrypt/gcrypt_dh.c | 4 +- src/libstrongswan/plugins/gcrypt/gcrypt_hasher.c | 15 +- src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c | 2 +- src/libstrongswan/plugins/gcrypt/gcrypt_rng.c | 6 +- .../plugins/gcrypt/gcrypt_rsa_private_key.c | 4 +- .../plugins/gcrypt/gcrypt_rsa_public_key.c | 4 +- src/libstrongswan/plugins/gmp/Makefile.in | 14 +- src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c | 9 +- .../plugins/gmp/gmp_rsa_private_key.c | 11 +- src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 22 +- src/libstrongswan/plugins/hmac/Makefile.am | 3 +- src/libstrongswan/plugins/hmac/Makefile.in | 22 +- src/libstrongswan/plugins/hmac/hmac.c | 123 +- src/libstrongswan/plugins/hmac/hmac.h | 78 +- src/libstrongswan/plugins/hmac/hmac_plugin.c | 3 +- src/libstrongswan/plugins/hmac/hmac_prf.c | 126 - src/libstrongswan/plugins/hmac/hmac_prf.h | 51 - src/libstrongswan/plugins/hmac/hmac_signer.c | 197 - src/libstrongswan/plugins/hmac/hmac_signer.h | 54 - src/libstrongswan/plugins/ldap/Makefile.in | 14 +- src/libstrongswan/plugins/ldap/ldap_fetcher.c | 7 +- src/libstrongswan/plugins/md4/Makefile.in | 14 +- src/libstrongswan/plugins/md4/md4_hasher.c | 32 +- src/libstrongswan/plugins/md5/Makefile.in | 14 +- src/libstrongswan/plugins/md5/md5_hasher.c | 44 +- src/libstrongswan/plugins/md5/md5_plugin.c | 2 - src/libstrongswan/plugins/mysql/Makefile.in | 14 +- src/libstrongswan/plugins/mysql/mysql_database.c | 1 + src/libstrongswan/plugins/nonce/Makefile.am | 16 + src/libstrongswan/plugins/nonce/Makefile.in | 617 ++ src/libstrongswan/plugins/nonce/nonce_nonceg.c | 84 + src/libstrongswan/plugins/nonce/nonce_nonceg.h | 46 + src/libstrongswan/plugins/nonce/nonce_plugin.c | 76 + src/libstrongswan/plugins/nonce/nonce_plugin.h | 42 + src/libstrongswan/plugins/openssl/Makefile.am | 4 +- src/libstrongswan/plugins/openssl/Makefile.in | 23 +- src/libstrongswan/plugins/openssl/openssl_crl.c | 7 +- .../plugins/openssl/openssl_crypter.c | 28 +- .../plugins/openssl/openssl_ec_public_key.c | 4 +- src/libstrongswan/plugins/openssl/openssl_hasher.c | 88 +- src/libstrongswan/plugins/openssl/openssl_hmac.c | 191 + src/libstrongswan/plugins/openssl/openssl_hmac.h | 45 + src/libstrongswan/plugins/openssl/openssl_plugin.c | 55 +- src/libstrongswan/plugins/openssl/openssl_rng.c | 100 + src/libstrongswan/plugins/openssl/openssl_rng.h | 54 + .../plugins/openssl/openssl_rsa_private_key.c | 3 +- .../plugins/openssl/openssl_rsa_public_key.c | 4 +- .../plugins/openssl/openssl_sha1_prf.c | 20 +- src/libstrongswan/plugins/openssl/openssl_x509.c | 13 +- src/libstrongswan/plugins/padlock/Makefile.in | 14 +- .../plugins/padlock/padlock_aes_crypter.c | 9 +- src/libstrongswan/plugins/padlock/padlock_rng.c | 6 +- .../plugins/padlock/padlock_sha1_hasher.c | 15 +- src/libstrongswan/plugins/pem/Makefile.in | 14 +- src/libstrongswan/plugins/pem/pem_builder.c | 26 +- src/libstrongswan/plugins/pem/pem_plugin.c | 26 +- src/libstrongswan/plugins/pgp/Makefile.in | 14 +- src/libstrongswan/plugins/pgp/pgp_cert.c | 10 +- src/libstrongswan/plugins/pgp/pgp_encoder.c | 8 +- src/libstrongswan/plugins/pkcs1/Makefile.in | 14 +- src/libstrongswan/plugins/pkcs1/pkcs1_encoder.c | 4 +- src/libstrongswan/plugins/pkcs11/Makefile.in | 14 +- src/libstrongswan/plugins/pkcs11/pkcs11_creds.c | 5 +- src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c | 47 +- src/libstrongswan/plugins/pkcs11/pkcs11_manager.c | 20 +- .../plugins/pkcs11/pkcs11_private_key.c | 8 +- .../plugins/pkcs11/pkcs11_public_key.c | 12 +- src/libstrongswan/plugins/pkcs11/pkcs11_rng.c | 14 +- src/libstrongswan/plugins/pkcs8/Makefile.in | 14 +- src/libstrongswan/plugins/pkcs8/pkcs8_builder.c | 60 +- src/libstrongswan/plugins/plugin_feature.c | 88 +- src/libstrongswan/plugins/plugin_feature.h | 49 +- src/libstrongswan/plugins/plugin_loader.c | 233 +- src/libstrongswan/plugins/plugin_loader.h | 24 + src/libstrongswan/plugins/pubkey/Makefile.in | 14 +- src/libstrongswan/plugins/pubkey/pubkey_cert.c | 7 +- src/libstrongswan/plugins/pubkey/pubkey_plugin.c | 5 + src/libstrongswan/plugins/random/Makefile.in | 14 +- src/libstrongswan/plugins/random/random_plugin.c | 70 + src/libstrongswan/plugins/random/random_plugin.h | 10 + src/libstrongswan/plugins/random/random_rng.c | 56 +- src/libstrongswan/plugins/revocation/Makefile.in | 14 +- .../plugins/revocation/revocation_validator.c | 6 +- src/libstrongswan/plugins/sha1/Makefile.in | 14 +- src/libstrongswan/plugins/sha1/sha1_hasher.c | 10 +- src/libstrongswan/plugins/sha1/sha1_prf.c | 17 +- src/libstrongswan/plugins/sha2/Makefile.in | 14 +- src/libstrongswan/plugins/sha2/sha2_hasher.c | 40 +- src/libstrongswan/plugins/soup/Makefile.in | 14 +- src/libstrongswan/plugins/sqlite/Makefile.in | 14 +- src/libstrongswan/plugins/sqlite/sqlite_database.c | 1 + src/libstrongswan/plugins/test_vectors/Makefile.in | 14 +- .../plugins/test_vectors/test_vectors.h | 1 + .../plugins/test_vectors/test_vectors/sha1.c | 6 + src/libstrongswan/plugins/x509/Makefile.in | 14 +- src/libstrongswan/plugins/x509/x509_ac.c | 6 +- src/libstrongswan/plugins/x509/x509_cert.c | 64 +- src/libstrongswan/plugins/x509/x509_crl.c | 8 +- src/libstrongswan/plugins/x509/x509_ocsp_request.c | 47 +- .../plugins/x509/x509_ocsp_response.c | 16 +- src/libstrongswan/plugins/x509/x509_pkcs10.c | 17 +- src/libstrongswan/plugins/x509/x509_plugin.c | 3 + src/libstrongswan/plugins/xcbc/Makefile.am | 3 +- src/libstrongswan/plugins/xcbc/Makefile.in | 22 +- src/libstrongswan/plugins/xcbc/xcbc.c | 148 +- src/libstrongswan/plugins/xcbc/xcbc.h | 60 +- src/libstrongswan/plugins/xcbc/xcbc_plugin.c | 3 +- src/libstrongswan/plugins/xcbc/xcbc_prf.c | 124 - src/libstrongswan/plugins/xcbc/xcbc_prf.h | 50 - src/libstrongswan/plugins/xcbc/xcbc_signer.c | 164 - src/libstrongswan/plugins/xcbc/xcbc_signer.h | 47 - src/libstrongswan/printf_hook.c | 42 +- src/libstrongswan/printf_hook.h | 126 +- src/libstrongswan/processing/jobs/callback_job.c | 186 +- src/libstrongswan/processing/jobs/callback_job.h | 66 +- src/libstrongswan/processing/jobs/job.h | 107 +- src/libstrongswan/processing/processor.c | 219 +- src/libstrongswan/processing/processor.h | 14 +- src/libstrongswan/processing/scheduler.c | 14 +- src/libstrongswan/selectors/traffic_selector.c | 94 +- src/libstrongswan/selectors/traffic_selector.h | 7 +- src/libstrongswan/settings.c | 11 +- src/libstrongswan/settings.h | 2 +- src/libstrongswan/threading/mutex.c | 40 +- src/libstrongswan/threading/rwlock.c | 233 +- src/libstrongswan/threading/rwlock_condvar.h | 90 + src/libstrongswan/threading/semaphore.c | 179 + src/libstrongswan/threading/semaphore.h | 85 + src/libstrongswan/threading/spinlock.c | 136 + src/libstrongswan/threading/spinlock.h | 58 + src/libstrongswan/threading/thread.c | 4 +- src/libstrongswan/threading/thread_value.c | 21 +- src/libstrongswan/utils.c | 99 +- src/libstrongswan/utils.h | 110 +- src/libstrongswan/utils/backtrace.c | 325 +- src/libstrongswan/utils/backtrace.h | 19 + src/libstrongswan/utils/blocking_queue.c | 129 + src/libstrongswan/utils/blocking_queue.h | 97 + src/libstrongswan/utils/capabilities.c | 291 + src/libstrongswan/utils/capabilities.h | 107 + src/libstrongswan/utils/enumerator.c | 12 +- src/libstrongswan/utils/enumerator.h | 5 +- src/libstrongswan/utils/hashtable.c | 26 +- src/libstrongswan/utils/hashtable.h | 18 +- src/libstrongswan/utils/host.c | 22 +- src/libstrongswan/utils/host.h | 15 +- src/libstrongswan/utils/identification.c | 34 +- src/libstrongswan/utils/identification.h | 4 +- src/libstrongswan/utils/leak_detective.c | 52 +- src/libstrongswan/utils/leak_detective.h | 8 + src/libstrongswan/utils/linked_list.c | 41 + src/libstrongswan/utils/linked_list.h | 17 + src/libstrongswan/utils/packet.c | 163 + src/libstrongswan/utils/packet.h | 121 + src/libstrongswan/utils/tun_device.c | 461 ++ src/libstrongswan/utils/tun_device.h | 112 + src/libtls/Makefile.am | 23 +- src/libtls/Makefile.in | 90 +- src/libtls/tls.h | 6 + src/libtls/tls_crypto.c | 96 +- src/libtls/tls_crypto.h | 3 +- src/libtls/tls_eap.c | 59 +- src/libtls/tls_fragmentation.c | 33 +- src/libtls/tls_peer.c | 39 +- src/libtls/tls_prf.c | 46 +- src/libtls/tls_prf.h | 6 +- src/libtls/tls_protection.c | 45 +- src/libtls/tls_server.c | 45 +- src/libtnccs/Makefile.in | 14 +- src/libtnccs/tnc/imv/imv_recommendations.h | 10 +- src/libtnccs/tnc/tnc.c | 14 +- src/libtnccs/tnc/tnccs/tnccs_manager.h | 2 + src/libtncif/Makefile.in | 14 +- src/manager/Makefile.in | 14 +- src/manager/storage.c | 6 +- src/medsrv/Makefile.in | 14 +- src/medsrv/controller/peer_controller.c | 0 src/medsrv/controller/peer_controller.h | 0 src/medsrv/controller/user_controller.c | 6 +- src/medsrv/controller/user_controller.h | 0 src/medsrv/filter/auth_filter.c | 0 src/medsrv/filter/auth_filter.h | 0 src/medsrv/templates/footer.cs | 0 src/medsrv/templates/header.cs | 0 src/medsrv/templates/peer/add.cs | 0 src/medsrv/templates/peer/edit.cs | 0 src/medsrv/templates/peer/list.cs | 0 src/medsrv/templates/static/favicon.ico | Bin src/medsrv/templates/static/strongswan.png | Bin src/medsrv/templates/static/style.css | 0 src/medsrv/templates/user/add.cs | 0 src/medsrv/templates/user/edit.cs | 0 src/medsrv/templates/user/login.cs | 0 src/openac/Makefile.in | 14 +- src/openac/openac.c | 0 src/pki/Makefile.in | 14 +- src/pki/command.c | 2 +- src/pki/commands/issue.c | 16 +- src/pki/commands/print.c | 4 + src/pki/commands/req.c | 4 +- src/pki/commands/self.c | 16 +- src/pki/commands/signcrl.c | 4 +- src/pki/commands/verify.c | 2 +- src/pki/pki.c | 32 - src/pki/pki.h | 5 - src/pluto/Android.mk | 80 - src/pluto/Makefile.am | 155 - src/pluto/Makefile.in | 1001 ---- src/pluto/ac.c | 298 - src/pluto/ac.h | 39 - src/pluto/adns.c | 610 -- src/pluto/adns.h | 78 - src/pluto/alg_info.c | 683 --- src/pluto/alg_info.h | 80 - src/pluto/builder.c | 150 - src/pluto/builder.h | 24 - src/pluto/ca.c | 712 --- src/pluto/ca.h | 58 - src/pluto/certs.c | 268 - src/pluto/certs.h | 80 - src/pluto/connections.c | 4507 --------------- src/pluto/connections.h | 366 -- src/pluto/constants.c | 1401 ----- src/pluto/constants.h | 1099 ---- src/pluto/cookie.c | 73 - src/pluto/cookie.h | 22 - src/pluto/crl.c | 541 -- src/pluto/crl.h | 53 - src/pluto/crypto.c | 698 --- src/pluto/crypto.h | 64 - src/pluto/db_ops.c | 412 -- src/pluto/db_ops.h | 54 - src/pluto/defs.c | 145 - src/pluto/defs.h | 79 - src/pluto/demux.c | 2527 --------- src/pluto/demux.h | 97 - src/pluto/dnskey.c | 1590 ------ src/pluto/dnskey.h | 75 - src/pluto/event_queue.c | 195 - src/pluto/event_queue.h | 69 - src/pluto/fetch.c | 766 --- src/pluto/fetch.h | 82 - src/pluto/foodgroups.c | 450 -- src/pluto/foodgroups.h | 22 - src/pluto/ike_alg.c | 452 -- src/pluto/ike_alg.h | 76 - src/pluto/ipsec_doi.c | 5921 -------------------- src/pluto/ipsec_doi.h | 108 - src/pluto/kameipsec.h | 47 - src/pluto/kernel.c | 2114 ------- src/pluto/kernel.h | 118 - src/pluto/kernel_alg.c | 663 --- src/pluto/kernel_alg.h | 43 - src/pluto/kernel_pfkey.c | 380 -- src/pluto/kernel_pfkey.h | 20 - src/pluto/keys.c | 1474 ----- src/pluto/keys.h | 93 - src/pluto/lex.c | 211 - src/pluto/lex.h | 50 - src/pluto/log.c | 946 ---- src/pluto/log.h | 234 - src/pluto/modecfg.c | 1263 ----- src/pluto/modecfg.h | 78 - src/pluto/myid.c | 121 - src/pluto/myid.h | 38 - src/pluto/nat_traversal.c | 845 --- src/pluto/nat_traversal.h | 152 - src/pluto/ocsp.c | 1558 ----- src/pluto/ocsp.h | 85 - src/pluto/packet.c | 1242 ---- src/pluto/packet.h | 653 --- src/pluto/pkcs7.c | 755 --- src/pluto/pkcs7.h | 53 - src/pluto/plugin_list.c | 72 - src/pluto/plugin_list.h | 21 - src/pluto/plugins/xauth/Makefile.am | 15 - src/pluto/plugins/xauth/Makefile.in | 603 -- src/pluto/plugins/xauth/xauth_default_provider.c | 66 - src/pluto/plugins/xauth/xauth_default_provider.h | 33 - src/pluto/plugins/xauth/xauth_default_verifier.c | 81 - src/pluto/plugins/xauth/xauth_default_verifier.h | 33 - src/pluto/plugins/xauth/xauth_plugin.c | 54 - src/pluto/plugins/xauth/xauth_plugin.h | 42 - src/pluto/pluto.8 | 1594 ------ src/pluto/pluto.c | 73 - src/pluto/pluto.h | 76 - src/pluto/plutomain.c | 852 --- src/pluto/rcv_whack.c | 728 --- src/pluto/rcv_whack.h | 15 - src/pluto/rsaref/pkcs11.h | 299 - src/pluto/rsaref/pkcs11f.h | 912 --- src/pluto/rsaref/pkcs11t.h | 1685 ------ src/pluto/rsaref/unix.h | 24 - src/pluto/server.c | 910 --- src/pluto/server.h | 56 - src/pluto/smartcard.c | 1940 ------- src/pluto/smartcard.h | 100 - src/pluto/spdb.c | 2315 -------- src/pluto/spdb.h | 110 - src/pluto/state.c | 952 ---- src/pluto/state.h | 274 - src/pluto/timer.c | 551 -- src/pluto/timer.h | 34 - src/pluto/vendor.c | 511 -- src/pluto/vendor.h | 137 - src/pluto/virtual.c | 325 -- src/pluto/virtual.h | 29 - src/pluto/whack_attribute.c | 365 -- src/pluto/whack_attribute.h | 111 - src/pluto/x509.c | 463 -- src/pluto/x509.h | 42 - src/pluto/xauth/xauth_manager.c | 127 - src/pluto/xauth/xauth_manager.h | 80 - src/pluto/xauth/xauth_provider.h | 56 - src/pluto/xauth/xauth_verifier.h | 56 - src/scepclient/Makefile.am | 47 +- src/scepclient/Makefile.in | 77 +- src/scepclient/loglite.c | 350 -- src/scepclient/scep.c | 360 +- src/scepclient/scep.h | 46 +- src/scepclient/scepclient.8 | 172 +- src/scepclient/scepclient.c | 865 ++- src/starter/Android.mk | 21 +- src/starter/Makefile.am | 25 +- src/starter/Makefile.in | 62 +- src/starter/args.c | 171 +- src/starter/cmp.c | 67 +- src/starter/cmp.h | 9 +- src/starter/confread.c | 684 +-- src/starter/confread.h | 121 +- src/starter/exec.c | 52 - src/starter/exec.h | 21 - src/starter/files.h | 4 - src/starter/interfaces.c | 213 - src/starter/interfaces.h | 36 - src/starter/invokecharon.c | 43 +- src/starter/invokepluto.c | 327 -- src/starter/invokepluto.h | 26 - src/starter/ipsec.conf | 10 +- src/starter/keywords.c | 283 +- src/starter/keywords.h | 91 +- src/starter/keywords.txt | 97 +- src/starter/klips.c | 26 +- src/starter/loglite.c | 297 - src/starter/netkey.c | 28 +- src/starter/parser.c | 46 +- src/starter/parser.h | 2 +- src/starter/parser.y | 18 +- src/starter/starter.c | 488 +- src/starter/starterstroke.c | 173 +- src/starter/starterstroke.h | 19 +- src/starter/starterwhack.c | 420 -- src/starter/starterwhack.h | 30 - src/stroke/Makefile.in | 14 +- src/stroke/stroke.c | 5 +- src/stroke/stroke_msg.h | 13 +- src/whack/Android.mk | 30 - src/whack/Makefile.am | 18 - src/whack/Makefile.in | 595 -- src/whack/whack.c | 1959 ------- src/whack/whack.h | 352 -- 1280 files changed, 80922 insertions(+), 111419 deletions(-) create mode 100644 src/charon-nm/Makefile.am create mode 100644 src/charon-nm/Makefile.in create mode 100644 src/charon-nm/charon-nm.c create mode 100644 src/charon-nm/nm/nm_backend.c create mode 100644 src/charon-nm/nm/nm_backend.h create mode 100644 src/charon-nm/nm/nm_creds.c create mode 100644 src/charon-nm/nm/nm_creds.h create mode 100644 src/charon-nm/nm/nm_handler.c create mode 100644 src/charon-nm/nm/nm_handler.h create mode 100644 src/charon-nm/nm/nm_service.c create mode 100644 src/charon-nm/nm/nm_service.h create mode 100644 src/ipsec/_ipsec.8 create mode 100644 src/ipsec/_ipsec.8.in create mode 100644 src/ipsec/_ipsec.in delete mode 100644 src/ipsec/ipsec.8 delete mode 100644 src/ipsec/ipsec.8.in delete mode 100755 src/ipsec/ipsec.in create mode 100644 src/libcharon/bus/listeners/logger.h create mode 100644 src/libcharon/encoding/payloads/hash_payload.c create mode 100644 src/libcharon/encoding/payloads/hash_payload.h delete mode 100644 src/libcharon/network/packet.c delete mode 100644 src/libcharon/network/packet.h delete mode 100644 src/libcharon/plugins/android/android_logger.c delete mode 100644 src/libcharon/plugins/android/android_logger.h create mode 100644 src/libcharon/plugins/android_log/Makefile.am create mode 100644 src/libcharon/plugins/android_log/Makefile.in create mode 100644 src/libcharon/plugins/android_log/android_log_logger.c create mode 100644 src/libcharon/plugins/android_log/android_log_logger.h create mode 100644 src/libcharon/plugins/android_log/android_log_plugin.c create mode 100644 src/libcharon/plugins/android_log/android_log_plugin.h create mode 100644 src/libcharon/plugins/eap_dynamic/Makefile.am create mode 100644 src/libcharon/plugins/eap_dynamic/Makefile.in create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic.c create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic.h create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c create mode 100644 src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h delete mode 100644 src/libcharon/plugins/nm/Makefile.am delete mode 100644 src/libcharon/plugins/nm/Makefile.in delete mode 100644 src/libcharon/plugins/nm/nm_creds.c delete mode 100644 src/libcharon/plugins/nm/nm_creds.h delete mode 100644 src/libcharon/plugins/nm/nm_handler.c delete mode 100644 src/libcharon/plugins/nm/nm_handler.h delete mode 100644 src/libcharon/plugins/nm/nm_plugin.c delete mode 100644 src/libcharon/plugins/nm/nm_plugin.h delete mode 100644 src/libcharon/plugins/nm/nm_service.c delete mode 100644 src/libcharon/plugins/nm/nm_service.h delete mode 100644 src/libcharon/plugins/socket_raw/Makefile.am delete mode 100644 src/libcharon/plugins/socket_raw/Makefile.in delete mode 100644 src/libcharon/plugins/socket_raw/socket_raw_plugin.c delete mode 100644 src/libcharon/plugins/socket_raw/socket_raw_plugin.h delete mode 100644 src/libcharon/plugins/socket_raw/socket_raw_socket.c delete mode 100644 src/libcharon/plugins/socket_raw/socket_raw_socket.h create mode 100644 src/libcharon/plugins/stroke/stroke_handler.c create mode 100644 src/libcharon/plugins/stroke/stroke_handler.h create mode 100644 src/libcharon/plugins/unity/Makefile.am create mode 100644 src/libcharon/plugins/unity/Makefile.in create mode 100644 src/libcharon/plugins/unity/unity_handler.c create mode 100644 src/libcharon/plugins/unity/unity_handler.h create mode 100644 src/libcharon/plugins/unity/unity_narrow.c create mode 100644 src/libcharon/plugins/unity/unity_narrow.h create mode 100644 src/libcharon/plugins/unity/unity_plugin.c create mode 100644 src/libcharon/plugins/unity/unity_plugin.h create mode 100644 src/libcharon/plugins/unity/unity_provider.c create mode 100644 src/libcharon/plugins/unity/unity_provider.h create mode 100644 src/libcharon/plugins/updown/updown_handler.c create mode 100644 src/libcharon/plugins/updown/updown_handler.h create mode 100644 src/libcharon/plugins/xauth_eap/Makefile.am create mode 100644 src/libcharon/plugins/xauth_eap/Makefile.in create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap.c create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap.h create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h create mode 100644 src/libcharon/plugins/xauth_generic/Makefile.am create mode 100644 src/libcharon/plugins/xauth_generic/Makefile.in create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic.c create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic.h create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h create mode 100644 src/libcharon/plugins/xauth_pam/Makefile.am create mode 100644 src/libcharon/plugins/xauth_pam/Makefile.in create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam.c create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam.h create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c create mode 100644 src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h create mode 100644 src/libcharon/processing/jobs/adopt_children_job.c create mode 100644 src/libcharon/processing/jobs/adopt_children_job.h create mode 100644 src/libcharon/processing/jobs/dpd_timeout_job.c create mode 100644 src/libcharon/processing/jobs/dpd_timeout_job.h create mode 100644 src/libcharon/processing/jobs/retry_initiate_job.c create mode 100644 src/libcharon/processing/jobs/retry_initiate_job.h create mode 100644 src/libcharon/sa/authenticator.c create mode 100644 src/libcharon/sa/authenticator.h delete mode 100644 src/libcharon/sa/authenticators/authenticator.c delete mode 100644 src/libcharon/sa/authenticators/authenticator.h delete mode 100644 src/libcharon/sa/authenticators/eap/eap_manager.c delete mode 100644 src/libcharon/sa/authenticators/eap/eap_manager.h delete mode 100644 src/libcharon/sa/authenticators/eap/eap_method.c delete mode 100644 src/libcharon/sa/authenticators/eap/eap_method.h delete mode 100644 src/libcharon/sa/authenticators/eap_authenticator.c delete mode 100644 src/libcharon/sa/authenticators/eap_authenticator.h delete mode 100644 src/libcharon/sa/authenticators/psk_authenticator.c delete mode 100644 src/libcharon/sa/authenticators/psk_authenticator.h delete mode 100644 src/libcharon/sa/authenticators/pubkey_authenticator.c delete mode 100644 src/libcharon/sa/authenticators/pubkey_authenticator.h delete mode 100644 src/libcharon/sa/connect_manager.c delete mode 100644 src/libcharon/sa/connect_manager.h create mode 100644 src/libcharon/sa/eap/eap_manager.c create mode 100644 src/libcharon/sa/eap/eap_manager.h create mode 100644 src/libcharon/sa/eap/eap_method.c create mode 100644 src/libcharon/sa/eap/eap_method.h create mode 100644 src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c create mode 100644 src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h create mode 100644 src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c create mode 100644 src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h create mode 100644 src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c create mode 100644 src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h create mode 100644 src/libcharon/sa/ikev1/keymat_v1.c create mode 100644 src/libcharon/sa/ikev1/keymat_v1.h create mode 100644 src/libcharon/sa/ikev1/phase1.c create mode 100644 src/libcharon/sa/ikev1/phase1.h create mode 100644 src/libcharon/sa/ikev1/task_manager_v1.c create mode 100644 src/libcharon/sa/ikev1/task_manager_v1.h create mode 100644 src/libcharon/sa/ikev1/tasks/aggressive_mode.c create mode 100644 src/libcharon/sa/ikev1/tasks/aggressive_mode.h create mode 100644 src/libcharon/sa/ikev1/tasks/informational.c create mode 100644 src/libcharon/sa/ikev1/tasks/informational.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_delete.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_delete.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_dpd.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_dpd.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_natd.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_natd.h create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_vendor.c create mode 100644 src/libcharon/sa/ikev1/tasks/isakmp_vendor.h create mode 100644 src/libcharon/sa/ikev1/tasks/main_mode.c create mode 100644 src/libcharon/sa/ikev1/tasks/main_mode.h create mode 100644 src/libcharon/sa/ikev1/tasks/mode_config.c create mode 100644 src/libcharon/sa/ikev1/tasks/mode_config.h create mode 100644 src/libcharon/sa/ikev1/tasks/quick_delete.c create mode 100644 src/libcharon/sa/ikev1/tasks/quick_delete.h create mode 100644 src/libcharon/sa/ikev1/tasks/quick_mode.c create mode 100644 src/libcharon/sa/ikev1/tasks/quick_mode.h create mode 100644 src/libcharon/sa/ikev1/tasks/xauth.c create mode 100644 src/libcharon/sa/ikev1/tasks/xauth.h create mode 100644 src/libcharon/sa/ikev2/authenticators/eap_authenticator.c create mode 100644 src/libcharon/sa/ikev2/authenticators/eap_authenticator.h create mode 100644 src/libcharon/sa/ikev2/authenticators/psk_authenticator.c create mode 100644 src/libcharon/sa/ikev2/authenticators/psk_authenticator.h create mode 100644 src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c create mode 100644 src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h create mode 100644 src/libcharon/sa/ikev2/connect_manager.c create mode 100644 src/libcharon/sa/ikev2/connect_manager.h create mode 100644 src/libcharon/sa/ikev2/keymat_v2.c create mode 100644 src/libcharon/sa/ikev2/keymat_v2.h create mode 100644 src/libcharon/sa/ikev2/mediation_manager.c create mode 100644 src/libcharon/sa/ikev2/mediation_manager.h create mode 100644 src/libcharon/sa/ikev2/task_manager_v2.c create mode 100644 src/libcharon/sa/ikev2/task_manager_v2.h create mode 100644 src/libcharon/sa/ikev2/tasks/child_create.c create mode 100644 src/libcharon/sa/ikev2/tasks/child_create.h create mode 100644 src/libcharon/sa/ikev2/tasks/child_delete.c create mode 100644 src/libcharon/sa/ikev2/tasks/child_delete.h create mode 100644 src/libcharon/sa/ikev2/tasks/child_rekey.c create mode 100644 src/libcharon/sa/ikev2/tasks/child_rekey.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_auth.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_auth.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_cert_post.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_cert_post.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_cert_pre.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_cert_pre.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_config.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_config.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_delete.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_delete.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_dpd.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_dpd.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_init.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_init.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_me.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_me.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_mobike.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_mobike.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_natd.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_natd.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_reauth.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_reauth.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_rekey.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_rekey.h create mode 100644 src/libcharon/sa/ikev2/tasks/ike_vendor.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_vendor.h delete mode 100644 src/libcharon/sa/mediation_manager.c delete mode 100644 src/libcharon/sa/mediation_manager.h create mode 100644 src/libcharon/sa/task.c create mode 100644 src/libcharon/sa/task.h delete mode 100644 src/libcharon/sa/tasks/child_create.c delete mode 100644 src/libcharon/sa/tasks/child_create.h delete mode 100644 src/libcharon/sa/tasks/child_delete.c delete mode 100644 src/libcharon/sa/tasks/child_delete.h delete mode 100644 src/libcharon/sa/tasks/child_rekey.c delete mode 100644 src/libcharon/sa/tasks/child_rekey.h delete mode 100644 src/libcharon/sa/tasks/ike_auth.c delete mode 100644 src/libcharon/sa/tasks/ike_auth.h delete mode 100644 src/libcharon/sa/tasks/ike_auth_lifetime.c delete mode 100644 src/libcharon/sa/tasks/ike_auth_lifetime.h delete mode 100644 src/libcharon/sa/tasks/ike_cert_post.c delete mode 100644 src/libcharon/sa/tasks/ike_cert_post.h delete mode 100644 src/libcharon/sa/tasks/ike_cert_pre.c delete mode 100644 src/libcharon/sa/tasks/ike_cert_pre.h delete mode 100644 src/libcharon/sa/tasks/ike_config.c delete mode 100644 src/libcharon/sa/tasks/ike_config.h delete mode 100644 src/libcharon/sa/tasks/ike_delete.c delete mode 100644 src/libcharon/sa/tasks/ike_delete.h delete mode 100644 src/libcharon/sa/tasks/ike_dpd.c delete mode 100644 src/libcharon/sa/tasks/ike_dpd.h delete mode 100644 src/libcharon/sa/tasks/ike_init.c delete mode 100644 src/libcharon/sa/tasks/ike_init.h delete mode 100644 src/libcharon/sa/tasks/ike_me.c delete mode 100644 src/libcharon/sa/tasks/ike_me.h delete mode 100644 src/libcharon/sa/tasks/ike_mobike.c delete mode 100644 src/libcharon/sa/tasks/ike_mobike.h delete mode 100644 src/libcharon/sa/tasks/ike_natd.c delete mode 100644 src/libcharon/sa/tasks/ike_natd.h delete mode 100644 src/libcharon/sa/tasks/ike_reauth.c delete mode 100644 src/libcharon/sa/tasks/ike_reauth.h delete mode 100644 src/libcharon/sa/tasks/ike_rekey.c delete mode 100644 src/libcharon/sa/tasks/ike_rekey.h delete mode 100644 src/libcharon/sa/tasks/ike_vendor.c delete mode 100644 src/libcharon/sa/tasks/ike_vendor.h delete mode 100644 src/libcharon/sa/tasks/task.c delete mode 100644 src/libcharon/sa/tasks/task.h create mode 100644 src/libcharon/sa/xauth/xauth_manager.c create mode 100644 src/libcharon/sa/xauth/xauth_manager.h create mode 100644 src/libcharon/sa/xauth/xauth_method.c create mode 100644 src/libcharon/sa/xauth/xauth_method.h delete mode 100644 src/libfreeswan/Android.mk delete mode 100644 src/libfreeswan/Makefile.am delete mode 100644 src/libfreeswan/Makefile.in delete mode 100644 src/libfreeswan/addrtoa.c delete mode 100644 src/libfreeswan/addrtot.c delete mode 100644 src/libfreeswan/addrtypeof.c delete mode 100644 src/libfreeswan/anyaddr.3 delete mode 100644 src/libfreeswan/anyaddr.c delete mode 100644 src/libfreeswan/atoaddr.3 delete mode 100644 src/libfreeswan/atoaddr.c delete mode 100644 src/libfreeswan/atoasr.3 delete mode 100644 src/libfreeswan/atoasr.c delete mode 100644 src/libfreeswan/atosubnet.c delete mode 100644 src/libfreeswan/atoul.3 delete mode 100644 src/libfreeswan/atoul.c delete mode 100644 src/libfreeswan/copyright.c delete mode 100644 src/libfreeswan/datatot.c delete mode 100644 src/libfreeswan/freeswan.h delete mode 100644 src/libfreeswan/goodmask.3 delete mode 100644 src/libfreeswan/goodmask.c delete mode 100644 src/libfreeswan/initaddr.3 delete mode 100644 src/libfreeswan/initaddr.c delete mode 100644 src/libfreeswan/initsaid.c delete mode 100644 src/libfreeswan/initsubnet.3 delete mode 100644 src/libfreeswan/initsubnet.c delete mode 100644 src/libfreeswan/internal.h delete mode 100644 src/libfreeswan/ipsec_param.h delete mode 100644 src/libfreeswan/pfkey.h delete mode 100644 src/libfreeswan/pfkey_v2_build.c delete mode 100644 src/libfreeswan/pfkey_v2_debug.c delete mode 100644 src/libfreeswan/pfkey_v2_ext_bits.c delete mode 100644 src/libfreeswan/pfkey_v2_parse.c delete mode 100644 src/libfreeswan/pfkeyv2.h delete mode 100644 src/libfreeswan/portof.3 delete mode 100644 src/libfreeswan/portof.c delete mode 100644 src/libfreeswan/rangetoa.c delete mode 100644 src/libfreeswan/rangetosubnet.3 delete mode 100644 src/libfreeswan/rangetosubnet.c delete mode 100644 src/libfreeswan/sameaddr.3 delete mode 100644 src/libfreeswan/sameaddr.c delete mode 100644 src/libfreeswan/satot.c delete mode 100644 src/libfreeswan/subnetof.3 delete mode 100644 src/libfreeswan/subnetof.c delete mode 100644 src/libfreeswan/subnettoa.c delete mode 100644 src/libfreeswan/subnettot.c delete mode 100644 src/libfreeswan/subnettypeof.c delete mode 100644 src/libfreeswan/ttoaddr.3 delete mode 100644 src/libfreeswan/ttoaddr.c delete mode 100644 src/libfreeswan/ttodata.3 delete mode 100644 src/libfreeswan/ttodata.c delete mode 100644 src/libfreeswan/ttoprotoport.c delete mode 100644 src/libfreeswan/ttosa.3 delete mode 100644 src/libfreeswan/ttosa.c delete mode 100644 src/libfreeswan/ttosubnet.c delete mode 100644 src/libfreeswan/ttoul.3 delete mode 100644 src/libfreeswan/ttoul.c delete mode 100644 src/libfreeswan/ultoa.c delete mode 100644 src/libfreeswan/ultot.c create mode 100644 src/libimcv/ietf/ietf_attr_assess_result.c create mode 100644 src/libimcv/ietf/ietf_attr_assess_result.h create mode 100644 src/libimcv/ietf/ietf_attr_attr_request.c create mode 100644 src/libimcv/ietf/ietf_attr_attr_request.h create mode 100644 src/libimcv/ita/ita_attr_dummy.c create mode 100644 src/libimcv/ita/ita_attr_dummy.h create mode 100644 src/libipsec/Android.mk create mode 100644 src/libipsec/Makefile.am create mode 100644 src/libipsec/Makefile.in create mode 100644 src/libipsec/esp_context.c create mode 100644 src/libipsec/esp_context.h create mode 100644 src/libipsec/esp_packet.c create mode 100644 src/libipsec/esp_packet.h create mode 100644 src/libipsec/ip_packet.c create mode 100644 src/libipsec/ip_packet.h create mode 100644 src/libipsec/ipsec.c create mode 100644 src/libipsec/ipsec.h create mode 100644 src/libipsec/ipsec_event_listener.h create mode 100644 src/libipsec/ipsec_event_relay.c create mode 100644 src/libipsec/ipsec_event_relay.h create mode 100644 src/libipsec/ipsec_policy.c create mode 100644 src/libipsec/ipsec_policy.h create mode 100644 src/libipsec/ipsec_policy_mgr.c create mode 100644 src/libipsec/ipsec_policy_mgr.h create mode 100644 src/libipsec/ipsec_processor.c create mode 100644 src/libipsec/ipsec_processor.h create mode 100644 src/libipsec/ipsec_sa.c create mode 100644 src/libipsec/ipsec_sa.h create mode 100644 src/libipsec/ipsec_sa_mgr.c create mode 100644 src/libipsec/ipsec_sa_mgr.h create mode 100755 src/libpts/plugins/imv_attestation/build-database.sh create mode 100644 src/libpts/pts/pts_pcr.c create mode 100644 src/libpts/pts/pts_pcr.h create mode 100644 src/libstrongswan/crypto/mac.h create mode 100644 src/libstrongswan/crypto/nonce_gen.h create mode 100644 src/libstrongswan/crypto/pkcs7.c create mode 100644 src/libstrongswan/crypto/pkcs7.h create mode 100644 src/libstrongswan/crypto/prfs/mac_prf.c create mode 100644 src/libstrongswan/crypto/prfs/mac_prf.h delete mode 100644 src/libstrongswan/crypto/proposal/proposal_keywords.txt create mode 100644 src/libstrongswan/crypto/proposal/proposal_keywords_static.c create mode 100644 src/libstrongswan/crypto/proposal/proposal_keywords_static.h create mode 100644 src/libstrongswan/crypto/proposal/proposal_keywords_static.txt create mode 100644 src/libstrongswan/crypto/signers/mac_signer.c create mode 100644 src/libstrongswan/crypto/signers/mac_signer.h create mode 100644 src/libstrongswan/ipsec/ipsec_types.c create mode 100644 src/libstrongswan/ipsec/ipsec_types.h delete mode 100644 src/libstrongswan/plugins/cmac/cmac_prf.c delete mode 100644 src/libstrongswan/plugins/cmac/cmac_prf.h delete mode 100644 src/libstrongswan/plugins/cmac/cmac_signer.c delete mode 100644 src/libstrongswan/plugins/cmac/cmac_signer.h delete mode 100644 src/libstrongswan/plugins/hmac/hmac_prf.c delete mode 100644 src/libstrongswan/plugins/hmac/hmac_prf.h delete mode 100644 src/libstrongswan/plugins/hmac/hmac_signer.c delete mode 100644 src/libstrongswan/plugins/hmac/hmac_signer.h create mode 100644 src/libstrongswan/plugins/nonce/Makefile.am create mode 100644 src/libstrongswan/plugins/nonce/Makefile.in create mode 100644 src/libstrongswan/plugins/nonce/nonce_nonceg.c create mode 100644 src/libstrongswan/plugins/nonce/nonce_nonceg.h create mode 100644 src/libstrongswan/plugins/nonce/nonce_plugin.c create mode 100644 src/libstrongswan/plugins/nonce/nonce_plugin.h create mode 100644 src/libstrongswan/plugins/openssl/openssl_hmac.c create mode 100644 src/libstrongswan/plugins/openssl/openssl_hmac.h create mode 100644 src/libstrongswan/plugins/openssl/openssl_rng.c create mode 100644 src/libstrongswan/plugins/openssl/openssl_rng.h delete mode 100644 src/libstrongswan/plugins/xcbc/xcbc_prf.c delete mode 100644 src/libstrongswan/plugins/xcbc/xcbc_prf.h delete mode 100644 src/libstrongswan/plugins/xcbc/xcbc_signer.c delete mode 100644 src/libstrongswan/plugins/xcbc/xcbc_signer.h create mode 100644 src/libstrongswan/threading/rwlock_condvar.h create mode 100644 src/libstrongswan/threading/semaphore.c create mode 100644 src/libstrongswan/threading/semaphore.h create mode 100644 src/libstrongswan/threading/spinlock.c create mode 100644 src/libstrongswan/threading/spinlock.h create mode 100644 src/libstrongswan/utils/blocking_queue.c create mode 100644 src/libstrongswan/utils/blocking_queue.h create mode 100644 src/libstrongswan/utils/capabilities.c create mode 100644 src/libstrongswan/utils/capabilities.h create mode 100644 src/libstrongswan/utils/packet.c create mode 100644 src/libstrongswan/utils/packet.h create mode 100644 src/libstrongswan/utils/tun_device.c create mode 100644 src/libstrongswan/utils/tun_device.h mode change 100755 => 100644 src/medsrv/controller/peer_controller.c mode change 100755 => 100644 src/medsrv/controller/peer_controller.h mode change 100755 => 100644 src/medsrv/controller/user_controller.c mode change 100755 => 100644 src/medsrv/controller/user_controller.h mode change 100755 => 100644 src/medsrv/filter/auth_filter.c mode change 100755 => 100644 src/medsrv/filter/auth_filter.h mode change 100755 => 100644 src/medsrv/templates/footer.cs mode change 100755 => 100644 src/medsrv/templates/header.cs mode change 100755 => 100644 src/medsrv/templates/peer/add.cs mode change 100755 => 100644 src/medsrv/templates/peer/edit.cs mode change 100755 => 100644 src/medsrv/templates/peer/list.cs mode change 100755 => 100644 src/medsrv/templates/static/favicon.ico mode change 100755 => 100644 src/medsrv/templates/static/strongswan.png mode change 100755 => 100644 src/medsrv/templates/static/style.css mode change 100755 => 100644 src/medsrv/templates/user/add.cs mode change 100755 => 100644 src/medsrv/templates/user/edit.cs mode change 100755 => 100644 src/medsrv/templates/user/login.cs mode change 100755 => 100644 src/openac/openac.c delete mode 100644 src/pluto/Android.mk delete mode 100644 src/pluto/Makefile.am delete mode 100644 src/pluto/Makefile.in delete mode 100644 src/pluto/ac.c delete mode 100644 src/pluto/ac.h delete mode 100644 src/pluto/adns.c delete mode 100644 src/pluto/adns.h delete mode 100644 src/pluto/alg_info.c delete mode 100644 src/pluto/alg_info.h delete mode 100644 src/pluto/builder.c delete mode 100644 src/pluto/builder.h delete mode 100644 src/pluto/ca.c delete mode 100644 src/pluto/ca.h delete mode 100644 src/pluto/certs.c delete mode 100644 src/pluto/certs.h delete mode 100644 src/pluto/connections.c delete mode 100644 src/pluto/connections.h delete mode 100644 src/pluto/constants.c delete mode 100644 src/pluto/constants.h delete mode 100644 src/pluto/cookie.c delete mode 100644 src/pluto/cookie.h delete mode 100644 src/pluto/crl.c delete mode 100644 src/pluto/crl.h delete mode 100644 src/pluto/crypto.c delete mode 100644 src/pluto/crypto.h delete mode 100644 src/pluto/db_ops.c delete mode 100644 src/pluto/db_ops.h delete mode 100644 src/pluto/defs.c delete mode 100644 src/pluto/defs.h delete mode 100644 src/pluto/demux.c delete mode 100644 src/pluto/demux.h delete mode 100644 src/pluto/dnskey.c delete mode 100644 src/pluto/dnskey.h delete mode 100644 src/pluto/event_queue.c delete mode 100644 src/pluto/event_queue.h delete mode 100644 src/pluto/fetch.c delete mode 100644 src/pluto/fetch.h delete mode 100644 src/pluto/foodgroups.c delete mode 100644 src/pluto/foodgroups.h delete mode 100644 src/pluto/ike_alg.c delete mode 100644 src/pluto/ike_alg.h delete mode 100644 src/pluto/ipsec_doi.c delete mode 100644 src/pluto/ipsec_doi.h delete mode 100644 src/pluto/kameipsec.h delete mode 100644 src/pluto/kernel.c delete mode 100644 src/pluto/kernel.h delete mode 100644 src/pluto/kernel_alg.c delete mode 100644 src/pluto/kernel_alg.h delete mode 100644 src/pluto/kernel_pfkey.c delete mode 100644 src/pluto/kernel_pfkey.h delete mode 100644 src/pluto/keys.c delete mode 100644 src/pluto/keys.h delete mode 100644 src/pluto/lex.c delete mode 100644 src/pluto/lex.h delete mode 100644 src/pluto/log.c delete mode 100644 src/pluto/log.h delete mode 100644 src/pluto/modecfg.c delete mode 100644 src/pluto/modecfg.h delete mode 100644 src/pluto/myid.c delete mode 100644 src/pluto/myid.h delete mode 100644 src/pluto/nat_traversal.c delete mode 100644 src/pluto/nat_traversal.h delete mode 100644 src/pluto/ocsp.c delete mode 100644 src/pluto/ocsp.h delete mode 100644 src/pluto/packet.c delete mode 100644 src/pluto/packet.h delete mode 100644 src/pluto/pkcs7.c delete mode 100644 src/pluto/pkcs7.h delete mode 100644 src/pluto/plugin_list.c delete mode 100644 src/pluto/plugin_list.h delete mode 100644 src/pluto/plugins/xauth/Makefile.am delete mode 100644 src/pluto/plugins/xauth/Makefile.in delete mode 100644 src/pluto/plugins/xauth/xauth_default_provider.c delete mode 100644 src/pluto/plugins/xauth/xauth_default_provider.h delete mode 100644 src/pluto/plugins/xauth/xauth_default_verifier.c delete mode 100644 src/pluto/plugins/xauth/xauth_default_verifier.h delete mode 100644 src/pluto/plugins/xauth/xauth_plugin.c delete mode 100644 src/pluto/plugins/xauth/xauth_plugin.h delete mode 100644 src/pluto/pluto.8 delete mode 100644 src/pluto/pluto.c delete mode 100644 src/pluto/pluto.h delete mode 100644 src/pluto/plutomain.c delete mode 100644 src/pluto/rcv_whack.c delete mode 100644 src/pluto/rcv_whack.h delete mode 100644 src/pluto/rsaref/pkcs11.h delete mode 100644 src/pluto/rsaref/pkcs11f.h delete mode 100644 src/pluto/rsaref/pkcs11t.h delete mode 100644 src/pluto/rsaref/unix.h delete mode 100644 src/pluto/server.c delete mode 100644 src/pluto/server.h delete mode 100644 src/pluto/smartcard.c delete mode 100644 src/pluto/smartcard.h delete mode 100644 src/pluto/spdb.c delete mode 100644 src/pluto/spdb.h delete mode 100644 src/pluto/state.c delete mode 100644 src/pluto/state.h delete mode 100644 src/pluto/timer.c delete mode 100644 src/pluto/timer.h delete mode 100644 src/pluto/vendor.c delete mode 100644 src/pluto/vendor.h delete mode 100644 src/pluto/virtual.c delete mode 100644 src/pluto/virtual.h delete mode 100644 src/pluto/whack_attribute.c delete mode 100644 src/pluto/whack_attribute.h delete mode 100644 src/pluto/x509.c delete mode 100644 src/pluto/x509.h delete mode 100644 src/pluto/xauth/xauth_manager.c delete mode 100644 src/pluto/xauth/xauth_manager.h delete mode 100644 src/pluto/xauth/xauth_provider.h delete mode 100644 src/pluto/xauth/xauth_verifier.h delete mode 100644 src/scepclient/loglite.c delete mode 100644 src/starter/exec.c delete mode 100644 src/starter/exec.h delete mode 100644 src/starter/interfaces.c delete mode 100644 src/starter/interfaces.h delete mode 100644 src/starter/invokepluto.c delete mode 100644 src/starter/invokepluto.h delete mode 100644 src/starter/loglite.c delete mode 100644 src/starter/starterwhack.c delete mode 100644 src/starter/starterwhack.h delete mode 100644 src/whack/Android.mk delete mode 100644 src/whack/Makefile.am delete mode 100644 src/whack/Makefile.in delete mode 100644 src/whack/whack.c delete mode 100644 src/whack/whack.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 1440de20f..e4c0374a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,6 +8,10 @@ if USE_LIBHYDRA SUBDIRS += libhydra endif +if USE_LIBIPSEC + SUBDIRS += libipsec +endif + if USE_SIMAKA SUBDIRS += libsimaka endif @@ -41,21 +45,21 @@ if USE_LIBCHARON endif if USE_FILE_CONFIG - SUBDIRS += libfreeswan starter + SUBDIRS += starter endif if USE_IPSEC_SCRIPT SUBDIRS += ipsec _copyright endif -if USE_PLUTO - SUBDIRS += pluto whack -endif - if USE_CHARON SUBDIRS += charon endif +if USE_NM + SUBDIRS += charon-nm +endif + if USE_STROKE SUBDIRS += stroke endif @@ -65,7 +69,7 @@ if USE_UPDOWN endif if USE_TOOLS - SUBDIRS += libfreeswan openac scepclient pki + SUBDIRS += openac scepclient pki endif if USE_CONFTEST diff --git a/src/Makefile.in b/src/Makefile.in index caa0c5bb9..939473424 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -35,27 +35,28 @@ build_triplet = @build@ host_triplet = @host@ @USE_LIBSTRONGSWAN_TRUE@am__append_1 = libstrongswan @USE_LIBHYDRA_TRUE@am__append_2 = libhydra -@USE_SIMAKA_TRUE@am__append_3 = libsimaka -@USE_TLS_TRUE@am__append_4 = libtls -@USE_RADIUS_TRUE@am__append_5 = libradius -@USE_LIBTNCIF_TRUE@am__append_6 = libtncif -@USE_LIBTNCCS_TRUE@am__append_7 = libtnccs -@USE_IMCV_TRUE@am__append_8 = libimcv -@USE_PTS_TRUE@am__append_9 = libpts -@USE_LIBCHARON_TRUE@am__append_10 = libcharon -@USE_FILE_CONFIG_TRUE@am__append_11 = libfreeswan starter -@USE_IPSEC_SCRIPT_TRUE@am__append_12 = ipsec _copyright -@USE_PLUTO_TRUE@am__append_13 = pluto whack +@USE_LIBIPSEC_TRUE@am__append_3 = libipsec +@USE_SIMAKA_TRUE@am__append_4 = libsimaka +@USE_TLS_TRUE@am__append_5 = libtls +@USE_RADIUS_TRUE@am__append_6 = libradius +@USE_LIBTNCIF_TRUE@am__append_7 = libtncif +@USE_LIBTNCCS_TRUE@am__append_8 = libtnccs +@USE_IMCV_TRUE@am__append_9 = libimcv +@USE_PTS_TRUE@am__append_10 = libpts +@USE_LIBCHARON_TRUE@am__append_11 = libcharon +@USE_FILE_CONFIG_TRUE@am__append_12 = starter +@USE_IPSEC_SCRIPT_TRUE@am__append_13 = ipsec _copyright @USE_CHARON_TRUE@am__append_14 = charon -@USE_STROKE_TRUE@am__append_15 = stroke -@USE_UPDOWN_TRUE@am__append_16 = _updown _updown_espmark -@USE_TOOLS_TRUE@am__append_17 = libfreeswan openac scepclient pki -@USE_CONFTEST_TRUE@am__append_18 = conftest -@USE_DUMM_TRUE@am__append_19 = dumm -@USE_FAST_TRUE@am__append_20 = libfast -@USE_MANAGER_TRUE@am__append_21 = manager -@USE_MEDSRV_TRUE@am__append_22 = medsrv -@USE_INTEGRITY_TEST_TRUE@am__append_23 = checksum +@USE_NM_TRUE@am__append_15 = charon-nm +@USE_STROKE_TRUE@am__append_16 = stroke +@USE_UPDOWN_TRUE@am__append_17 = _updown _updown_espmark +@USE_TOOLS_TRUE@am__append_18 = openac scepclient pki +@USE_CONFTEST_TRUE@am__append_19 = conftest +@USE_DUMM_TRUE@am__append_20 = dumm +@USE_FAST_TRUE@am__append_21 = libfast +@USE_MANAGER_TRUE@am__append_22 = manager +@USE_MEDSRV_TRUE@am__append_23 = medsrv +@USE_INTEGRITY_TEST_TRUE@am__append_24 = checksum subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -71,6 +72,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = @@ -89,11 +91,11 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ distdir ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = . include libstrongswan libhydra libsimaka libtls \ - libradius libtncif libtnccs libimcv libpts libcharon \ - libfreeswan starter ipsec _copyright pluto whack charon stroke \ - _updown _updown_espmark openac scepclient pki conftest dumm \ - libfast manager medsrv checksum +DIST_SUBDIRS = . include libstrongswan libhydra libipsec libsimaka \ + libtls libradius libtncif libtnccs libimcv libpts libcharon \ + starter ipsec _copyright charon charon-nm stroke _updown \ + _updown_espmark openac scepclient pki conftest dumm libfast \ + manager medsrv checksum DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ @@ -128,6 +130,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -222,11 +225,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -243,11 +249,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -263,6 +270,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -272,7 +280,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -307,7 +314,7 @@ SUBDIRS = . include $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_13) $(am__append_14) $(am__append_15) \ $(am__append_16) $(am__append_17) $(am__append_18) \ $(am__append_19) $(am__append_20) $(am__append_21) \ - $(am__append_22) $(am__append_23) + $(am__append_22) $(am__append_23) $(am__append_24) EXTRA_DIST = strongswan.conf all: all-recursive diff --git a/src/_copyright/Makefile.am b/src/_copyright/Makefile.am index 405e08b3d..915b57421 100644 --- a/src/_copyright/Makefile.am +++ b/src/_copyright/Makefile.am @@ -2,7 +2,6 @@ ipsec_PROGRAMS = _copyright _copyright_SOURCES = _copyright.c INCLUDES = \ --I$(top_srcdir)/src/libfreeswan \ -I$(top_srcdir)/src/libstrongswan -_copyright_LDADD = $(top_builddir)/src/libfreeswan/libfreeswan.a $(top_builddir)/src/libstrongswan/libstrongswan.la +_copyright_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la diff --git a/src/_copyright/Makefile.in b/src/_copyright/Makefile.in index ae15d3cde..c4477f303 100644 --- a/src/_copyright/Makefile.in +++ b/src/_copyright/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" @@ -57,9 +58,8 @@ PROGRAMS = $(ipsec_PROGRAMS) am__copyright_OBJECTS = _copyright.$(OBJEXT) _copyright_OBJECTS = $(am__copyright_OBJECTS) _copyright_DEPENDENCIES = \ - $(top_builddir)/src/libfreeswan/libfreeswan.a \ $(top_builddir)/src/libstrongswan/libstrongswan.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -85,6 +85,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -179,11 +180,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -200,11 +204,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -220,6 +225,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -229,7 +235,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -259,10 +264,9 @@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ _copyright_SOURCES = _copyright.c INCLUDES = \ --I$(top_srcdir)/src/libfreeswan \ -I$(top_srcdir)/src/libstrongswan -_copyright_LDADD = $(top_builddir)/src/libfreeswan/libfreeswan.a $(top_builddir)/src/libstrongswan/libstrongswan.la +_copyright_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la all: all-am .SUFFIXES: diff --git a/src/_copyright/_copyright.c b/src/_copyright/_copyright.c index 072998345..b20b17256 100644 --- a/src/_copyright/_copyright.c +++ b/src/_copyright/_copyright.c @@ -21,9 +21,41 @@ #include #include -#include #include +static const char *copyright[] = { + "Copyright (C) 1999-2012", + " Henry Spencer, D. Hugh Redelmeier, Michael Richardson, Ken Bantoft,", + " Stephen J. Bevan, JuanJo Ciarlante, Thomas Egerer, Heiko Hund,", + " Mathieu Lafon, Stephane Laroche, Kai Martius, Stephan Scholz,", + " Tuomo Soini, Herbert Xu.", + "", + " Martin Berner, Marco Bertossa, David Buechi, Ueli Galizzi,", + " Christoph Gysin, Andreas Hess, Patric Lichtsteiner, Michael Meier,", + " Andreas Schleiss, Ariane Seiler, Mario Strasser, Lukas Suter,", + " Roger Wegmann, Simon Zwahlen,", + " ZHW Zuercher Hochschule Winterthur (Switzerland).", + "", + " Philip Boetschi, Tobias Brunner, Sansar Choinyambuu, Adrian Doerig,", + " Andreas Eigenmann, Giuliano Grassi, Reto Guadagnini, Fabian Hartmann,", + " Noah Heusser, Jan Hutter, Thomas Kallenberg, Daniel Roethlisberger,", + " Ralf Sager, Joel Stillhart, Daniel Wydler, Andreas Steffen,", + " HSR Hochschule fuer Technik Rapperswil (Switzerland).", + "", + " Martin Willi (revosec AG), Clavister (Sweden).", + "", + "This program is free software; you can redistribute it and/or modify it", + "under the terms of the GNU General Public License as published by the", + "Free Software Foundation; either version 2 of the License, or (at your", + "option) any later version. See .", + "", + "This program is distributed in the hope that it will be useful, but", + "WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General", + "Public License (file COPYING in the distribution) for more details.", + NULL, +}; + char usage[] = "Usage: ipsec _copyright"; struct option opts[] = { {"help", 0, NULL, 'h',}, @@ -39,7 +71,7 @@ main(int argc, char *argv[]) int opt; extern int optind; int errflg = 0; - const char **notice = ipsec_copyright_notice(); + const char **notice = copyright; const char **co; library_init(NULL); diff --git a/src/_updown/Makefile.in b/src/_updown/Makefile.in index a406d79ac..672285ad0 100644 --- a/src/_updown/Makefile.in +++ b/src/_updown/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,6 +90,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -183,11 +185,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -204,11 +209,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -224,6 +230,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -233,7 +240,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/_updown/_updown.in b/src/_updown/_updown.in index 2c742c010..3a40e2110 100644 --- a/src/_updown/_updown.in +++ b/src/_updown/_updown.in @@ -73,8 +73,12 @@ # just the host, this will be 255.255.255.255. # # PLUTO_MY_SOURCEIP -# if non-empty, then the source address for the route will be -# set to this IP address. +# PLUTO_MY_SOURCEIP4_$i +# PLUTO_MY_SOURCEIP6_$i +# contains IPv4/IPv6 virtual IP received from a responder, +# $i enumerates from 1 to the number of IP per address family. +# PLUTO_MY_SOURCEIP is a legacy variable and equals to the first +# virtual IP, IPv4 or IPv6. # # PLUTO_MY_PROTOCOL # is the IP protocol that will be transported. @@ -128,6 +132,12 @@ # contains the remote UDP port in the case of ESP_IN_UDP # encapsulation # +# PLUTO_DNS4_$i +# PLUTO_DNS6_$i +# contains IPv4/IPv6 DNS server attribute received from a +# responder, $i enumerates from 1 to the number of servers per +# address family. +# # define a minimum PATH environment in case it is not set PATH="/sbin:/bin:/usr/sbin:/usr/bin:@sbindir@" diff --git a/src/_updown_espmark/Makefile.in b/src/_updown_espmark/Makefile.in index 3ae236a90..b62ceba2b 100644 --- a/src/_updown_espmark/Makefile.in +++ b/src/_updown_espmark/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,6 +90,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -183,11 +185,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -204,11 +209,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -224,6 +230,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -233,7 +240,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/charon-nm/Makefile.am b/src/charon-nm/Makefile.am new file mode 100644 index 000000000..80fc13ba1 --- /dev/null +++ b/src/charon-nm/Makefile.am @@ -0,0 +1,26 @@ +ipsec_PROGRAMS = charon-nm + +charon_nm_SOURCES = \ +charon-nm.c \ +nm/nm_backend.c nm/nm_backend.h \ +nm/nm_creds.c nm/nm_creds.h \ +nm/nm_handler.c nm/nm_handler.h \ +nm/nm_service.c nm/nm_service.h + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ + ${nm_CFLAGS} + +AM_CFLAGS = \ + -DIPSEC_DIR=\"${ipsecdir}\" \ + -DIPSEC_PIDDIR=\"${piddir}\" \ + -DNM_CA_DIR=\"${nm_ca_dir}\" \ + -DPLUGINS=\""${nm_plugins}\"" + +charon_nm_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libhydra/libhydra.la \ + $(top_builddir)/src/libcharon/libcharon.la \ + -lm $(PTHREADLIB) $(DLLIB) ${nm_LIBS} diff --git a/src/charon-nm/Makefile.in b/src/charon-nm/Makefile.in new file mode 100644 index 000000000..be72892e9 --- /dev/null +++ b/src/charon-nm/Makefile.in @@ -0,0 +1,676 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +ipsec_PROGRAMS = charon-nm$(EXEEXT) +subdir = src/charon-nm +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(ipsecdir)" +PROGRAMS = $(ipsec_PROGRAMS) +am_charon_nm_OBJECTS = charon-nm.$(OBJEXT) nm_backend.$(OBJEXT) \ + nm_creds.$(OBJEXT) nm_handler.$(OBJEXT) nm_service.$(OBJEXT) +charon_nm_OBJECTS = $(am_charon_nm_OBJECTS) +am__DEPENDENCIES_1 = +charon_nm_DEPENDENCIES = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libhydra/libhydra.la \ + $(top_builddir)/src/libcharon/libcharon.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(charon_nm_SOURCES) +DIST_SOURCES = $(charon_nm_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +charon_nm_SOURCES = \ +charon-nm.c \ +nm/nm_backend.c nm/nm_backend.h \ +nm/nm_creds.c nm/nm_creds.h \ +nm/nm_handler.c nm/nm_handler.h \ +nm/nm_service.c nm/nm_service.h + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ + ${nm_CFLAGS} + +AM_CFLAGS = \ + -DIPSEC_DIR=\"${ipsecdir}\" \ + -DIPSEC_PIDDIR=\"${piddir}\" \ + -DNM_CA_DIR=\"${nm_ca_dir}\" \ + -DPLUGINS=\""${nm_plugins}\"" + +charon_nm_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libhydra/libhydra.la \ + $(top_builddir)/src/libcharon/libcharon.la \ + -lm $(PTHREADLIB) $(DLLIB) ${nm_LIBS} + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/charon-nm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/charon-nm/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-ipsecPROGRAMS: $(ipsec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ipsecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ipsecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-ipsecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(ipsecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(ipsecdir)" && rm -f $$files + +clean-ipsecPROGRAMS: + @list='$(ipsec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +charon-nm$(EXEEXT): $(charon_nm_OBJECTS) $(charon_nm_DEPENDENCIES) + @rm -f charon-nm$(EXEEXT) + $(LINK) $(charon_nm_OBJECTS) $(charon_nm_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/charon-nm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_backend.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_creds.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_handler.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_service.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +nm_backend.o: nm/nm_backend.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_backend.o -MD -MP -MF $(DEPDIR)/nm_backend.Tpo -c -o nm_backend.o `test -f 'nm/nm_backend.c' || echo '$(srcdir)/'`nm/nm_backend.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_backend.Tpo $(DEPDIR)/nm_backend.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_backend.c' object='nm_backend.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_backend.o `test -f 'nm/nm_backend.c' || echo '$(srcdir)/'`nm/nm_backend.c + +nm_backend.obj: nm/nm_backend.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_backend.obj -MD -MP -MF $(DEPDIR)/nm_backend.Tpo -c -o nm_backend.obj `if test -f 'nm/nm_backend.c'; then $(CYGPATH_W) 'nm/nm_backend.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_backend.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_backend.Tpo $(DEPDIR)/nm_backend.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_backend.c' object='nm_backend.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_backend.obj `if test -f 'nm/nm_backend.c'; then $(CYGPATH_W) 'nm/nm_backend.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_backend.c'; fi` + +nm_creds.o: nm/nm_creds.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_creds.o -MD -MP -MF $(DEPDIR)/nm_creds.Tpo -c -o nm_creds.o `test -f 'nm/nm_creds.c' || echo '$(srcdir)/'`nm/nm_creds.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_creds.Tpo $(DEPDIR)/nm_creds.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_creds.c' object='nm_creds.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_creds.o `test -f 'nm/nm_creds.c' || echo '$(srcdir)/'`nm/nm_creds.c + +nm_creds.obj: nm/nm_creds.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_creds.obj -MD -MP -MF $(DEPDIR)/nm_creds.Tpo -c -o nm_creds.obj `if test -f 'nm/nm_creds.c'; then $(CYGPATH_W) 'nm/nm_creds.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_creds.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_creds.Tpo $(DEPDIR)/nm_creds.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_creds.c' object='nm_creds.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_creds.obj `if test -f 'nm/nm_creds.c'; then $(CYGPATH_W) 'nm/nm_creds.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_creds.c'; fi` + +nm_handler.o: nm/nm_handler.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_handler.o -MD -MP -MF $(DEPDIR)/nm_handler.Tpo -c -o nm_handler.o `test -f 'nm/nm_handler.c' || echo '$(srcdir)/'`nm/nm_handler.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_handler.Tpo $(DEPDIR)/nm_handler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_handler.c' object='nm_handler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_handler.o `test -f 'nm/nm_handler.c' || echo '$(srcdir)/'`nm/nm_handler.c + +nm_handler.obj: nm/nm_handler.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_handler.obj -MD -MP -MF $(DEPDIR)/nm_handler.Tpo -c -o nm_handler.obj `if test -f 'nm/nm_handler.c'; then $(CYGPATH_W) 'nm/nm_handler.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_handler.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_handler.Tpo $(DEPDIR)/nm_handler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_handler.c' object='nm_handler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_handler.obj `if test -f 'nm/nm_handler.c'; then $(CYGPATH_W) 'nm/nm_handler.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_handler.c'; fi` + +nm_service.o: nm/nm_service.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_service.o -MD -MP -MF $(DEPDIR)/nm_service.Tpo -c -o nm_service.o `test -f 'nm/nm_service.c' || echo '$(srcdir)/'`nm/nm_service.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_service.Tpo $(DEPDIR)/nm_service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_service.c' object='nm_service.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_service.o `test -f 'nm/nm_service.c' || echo '$(srcdir)/'`nm/nm_service.c + +nm_service.obj: nm/nm_service.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm_service.obj -MD -MP -MF $(DEPDIR)/nm_service.Tpo -c -o nm_service.obj `if test -f 'nm/nm_service.c'; then $(CYGPATH_W) 'nm/nm_service.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_service.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/nm_service.Tpo $(DEPDIR)/nm_service.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nm/nm_service.c' object='nm_service.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm_service.obj `if test -f 'nm/nm_service.c'; then $(CYGPATH_W) 'nm/nm_service.c'; else $(CYGPATH_W) '$(srcdir)/nm/nm_service.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(ipsecdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-ipsecPROGRAMS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-ipsecPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-ipsecPROGRAMS clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-ipsecPROGRAMS install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-ipsecPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/charon-nm/charon-nm.c b/src/charon-nm/charon-nm.c new file mode 100644 index 000000000..35e906778 --- /dev/null +++ b/src/charon-nm/charon-nm.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +/** + * Hook in library for debugging messages + */ +extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); + +/** + * Simple logging hook for library logs, using syslog output + */ +static void dbg_syslog(debug_t group, level_t level, char *fmt, ...) +{ + if (level <= 1) + { + char buffer[8192], groupstr[4]; + va_list args; + + va_start(args, fmt); + /* write in memory buffer first */ + vsnprintf(buffer, sizeof(buffer), fmt, args); + /* cache group name */ + snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group); + syslog(LOG_DAEMON|LOG_INFO, "00[%s] %s", groupstr, buffer); + va_end(args); + } +} + +/** + * Run the daemon and handle unix signals + */ +static void run() +{ + sigset_t set; + + /* handle SIGINT and SIGTERM in this handler */ + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, NULL); + + while (TRUE) + { + int sig; + int error; + + error = sigwait(&set, &sig); + if (error) + { + DBG1(DBG_DMN, "error %d while waiting for a signal", error); + return; + } + switch (sig) + { + case SIGINT: + { + DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return; + } + case SIGTERM: + { + DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return; + } + default: + { + DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig); + break; + } + } + } +} + +/** + * Handle SIGSEGV/SIGILL signals raised by threads + */ +static void segv_handler(int signal) +{ + backtrace_t *backtrace; + + DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); + backtrace = backtrace_create(2); + backtrace->log(backtrace, stderr, TRUE); + backtrace->destroy(backtrace); + + DBG1(DBG_DMN, "killing ourself, received critical signal"); + abort(); +} + +/** + * Initialize logging to syslog + */ +static void initialize_logger() +{ + sys_logger_t *sys_logger; + debug_t group; + level_t def; + + sys_logger = sys_logger_create(LOG_DAEMON, FALSE); + def = lib->settings->get_int(lib->settings, + "charon-nm.syslog.default", 1); + for (group = 0; group < DBG_MAX; group++) + { + sys_logger->set_level(sys_logger, group, + lib->settings->get_int(lib->settings, "charon-nm.syslog.%N", def, + debug_lower_names, group)); + } + charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger); + charon->bus->add_logger(charon->bus, &sys_logger->logger); +} + +/** + * Lookup UID and GID + */ +static bool lookup_uid_gid() +{ +#ifdef IPSEC_USER + if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + { + return FALSE; + } +#endif +#ifdef IPSEC_GROUP + if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + { + return FALSE; + } +#endif + return TRUE; +} + +/** + * Main function, starts NetworkManager backend. + */ +int main(int argc, char *argv[]) +{ + struct sigaction action; + int status = SS_RC_INITIALIZATION_FAILED; + + /* logging for library during initialization, as we have no bus yet */ + dbg = dbg_syslog; + + /* initialize library */ + if (!library_init(NULL)) + { + library_deinit(); + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + + if (lib->integrity && + !lib->integrity->check_file(lib->integrity, "charon-nm", argv[0])) + { + dbg_syslog(DBG_DMN, 1, "integrity check of charon-nm failed"); + library_deinit(); + exit(SS_RC_DAEMON_INTEGRITY); + } + + if (!libhydra_init("charon-nm")) + { + dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm"); + libhydra_deinit(); + library_deinit(); + exit(SS_RC_INITIALIZATION_FAILED); + } + + if (!libcharon_init("charon-nm")) + { + dbg_syslog(DBG_DMN, 1, "initialization failed - aborting charon-nm"); + goto deinit; + } + + if (!lookup_uid_gid()) + { + dbg_syslog(DBG_DMN, 1, "invalid uid/gid - aborting charon-nm"); + goto deinit; + } + + initialize_logger(); + + /* use random ports to avoid conflicts with regular charon */ + lib->settings->set_int(lib->settings, "charon-nm.port", 0); + lib->settings->set_int(lib->settings, "charon-nm.port_natt_t", 0); + + DBG1(DBG_DMN, "Starting charon NetworkManager backend (strongSwan "VERSION")"); + if (lib->integrity) + { + DBG1(DBG_DMN, "integrity tests enabled:"); + DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); + DBG1(DBG_DMN, "lib 'libhydra': passed file and segment integrity tests"); + DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); + DBG1(DBG_DMN, "daemon 'charon-nm': passed file integrity test"); + } + + /* register NM backend to be loaded with plugins */ + nm_backend_register(); + + /* initialize daemon */ + if (!charon->initialize(charon, + lib->settings->get_str(lib->settings, "charon-nm.load", PLUGINS))) + { + DBG1(DBG_DMN, "initialization failed - aborting charon-nm"); + goto deinit; + } + + if (!charon->caps->drop(charon->caps)) + { + DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm"); + goto deinit; + } + + /* add handler for SEGV and ILL, + * INT and TERM are handled by sigwait() in run() */ + action.sa_handler = segv_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGTERM); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGBUS, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); + + /* start daemon (i.e. the threads in the thread-pool) */ + charon->start(charon); + + /* main thread goes to run loop */ + run(); + + status = 0; + +deinit: + libcharon_deinit(); + libhydra_deinit(); + library_deinit(); + return status; +} + diff --git a/src/charon-nm/nm/nm_backend.c b/src/charon-nm/nm/nm_backend.c new file mode 100644 index 000000000..f36cf1f68 --- /dev/null +++ b/src/charon-nm/nm/nm_backend.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2008-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "nm_service.h" +#include "nm_creds.h" +#include "nm_handler.h" + +#include +#include +#include + +#ifndef CAP_DAC_OVERRIDE +#define CAP_DAC_OVERRIDE 1 +#endif + +typedef struct nm_backend_t nm_backend_t; + +/** + * Data for the NetworkManager backend. + */ +struct nm_backend_t { + + /** + * NetworkManager service (VPNPlugin) + */ + NMStrongswanPlugin *plugin; + + /** + * Glib main loop for a thread, handles DBUS calls + */ + GMainLoop *loop; + + /** + * credential set registered at the daemon + */ + nm_creds_t *creds; + + /** + * attribute handler regeisterd at the daemon + */ + nm_handler_t *handler; +}; + +/** + * Global (but private) instance of the NM backend. + */ +static nm_backend_t *nm_backend = NULL; + +/** + * NM plugin processing routine, creates and handles NMVPNPlugin + */ +static job_requeue_t run(nm_backend_t *this) +{ + this->loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(this->loop); + return JOB_REQUEUE_NONE; +} + +/** + * Cancel the GLib Main Event Loop + */ +static bool cancel(nm_backend_t *this) +{ + if (this->loop) + { + if (g_main_loop_is_running(this->loop)) + { + g_main_loop_quit(this->loop); + } + g_main_loop_unref(this->loop); + } + return TRUE; +} + +/** + * Deinitialize NetworkManager backend + */ +static void nm_backend_deinit() +{ + nm_backend_t *this = nm_backend; + + if (!this) + { + return; + } + if (this->plugin) + { + g_object_unref(this->plugin); + } + lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler); + this->creds->destroy(this->creds); + this->handler->destroy(this->handler); + free(this); + + nm_backend = NULL; +} + +/** + * Initialize NetworkManager backend + */ +static bool nm_backend_init() +{ + nm_backend_t *this; + + g_type_init (); + if (!g_thread_supported()) + { + g_thread_init(NULL); + } + + INIT(this, + .creds = nm_creds_create(), + .handler = nm_handler_create(), + ); + this->plugin = nm_strongswan_plugin_new(this->creds, this->handler); + nm_backend = this; + + hydra->attributes->add_handler(hydra->attributes, &this->handler->handler); + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + if (!this->plugin) + { + DBG1(DBG_CFG, "DBUS binding failed"); + nm_backend_deinit(); + return FALSE; + } + + /* bypass file permissions to read from users ssh-agent */ + charon->caps->keep(charon->caps, CAP_DAC_OVERRIDE); + + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)run, this, + NULL, (callback_job_cancel_t)cancel, JOB_PRIO_CRITICAL)); + return TRUE; +} + +/** + * Initialize/deinitialize NetworkManager backend + */ +static bool nm_backend_cb(void *plugin, + plugin_feature_t *feature, bool reg, void *data) +{ + if (reg) + { + return nm_backend_init(); + } + nm_backend_deinit(); + return TRUE; +} + +/* + * see header file + */ +void nm_backend_register() +{ + static plugin_feature_t features[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)nm_backend_cb, NULL), + PLUGIN_PROVIDE(CUSTOM, "NetworkManager backend"), + PLUGIN_DEPENDS(CUSTOM, "libcharon"), + }; + lib->plugins->add_static_features(lib->plugins, "nm-backend", features, + countof(features), TRUE); +} diff --git a/src/charon-nm/nm/nm_backend.h b/src/charon-nm/nm/nm_backend.h new file mode 100644 index 000000000..89dc536f6 --- /dev/null +++ b/src/charon-nm/nm/nm_backend.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup charon-nm charon-nm + * + * @defgroup nm nm + * @ingroup charon-nm + * + * @defgroup nm_backend nm_backend + * @{ @ingroup nm + */ + +#ifndef NM_BACKEND_H_ +#define NM_BACKEND_H_ + +/** + * Initialize the NetworkManager backend. + * + * @return TRUE, if initialization was successful + */ +void nm_backend_register(); + +#endif /** NM_BACKEND_H_ @}*/ diff --git a/src/charon-nm/nm/nm_creds.c b/src/charon-nm/nm/nm_creds.c new file mode 100644 index 000000000..f8fae9504 --- /dev/null +++ b/src/charon-nm/nm/nm_creds.c @@ -0,0 +1,490 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "nm_creds.h" + +#include +#include +#include + +#include +#include +#include + +typedef struct private_nm_creds_t private_nm_creds_t; + +/** + * private data of nm_creds + */ +struct private_nm_creds_t { + + /** + * public functions + */ + nm_creds_t public; + + /** + * List of trusted certificates, certificate_t* + */ + linked_list_t *certs; + + /** + * User name + */ + identification_t *user; + + /** + * User password + */ + char *pass; + + /** + * Private key decryption password / smartcard pin + */ + char *keypass; + + /** + * private key ID of smartcard key + */ + chunk_t keyid; + + /** + * users certificate + */ + certificate_t *usercert; + + /** + * users private key + */ + private_key_t *key; + + /** + * read/write lock + */ + rwlock_t *lock; +}; + +/** + * Enumerator for user certificate + */ +static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this, + certificate_type_t cert, key_type_t key) +{ + public_key_t *public; + + if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert)) + { + return NULL; + } + if (key != KEY_ANY) + { + public = this->usercert->get_public_key(this->usercert); + if (!public) + { + return NULL; + } + if (public->get_type(public) != key) + { + public->destroy(public); + return NULL; + } + public->destroy(public); + } + this->lock->read_lock(this->lock); + return enumerator_create_cleaner( + enumerator_create_single(this->usercert, NULL), + (void*)this->lock->unlock, this->lock); +} + +/** + * CA certificate enumerator data + */ +typedef struct { + /** ref to credential credential store */ + private_nm_creds_t *this; + /** type of key we are looking for */ + key_type_t key; + /** CA certificate ID */ + identification_t *id; +} cert_data_t; + +/** + * Destroy CA certificate enumerator data + */ +static void cert_data_destroy(cert_data_t *data) +{ + data->this->lock->unlock(data->this->lock); + free(data); +} + +/** + * Filter function for certificates enumerator + */ +static bool cert_filter(cert_data_t *data, certificate_t **in, + certificate_t **out) +{ + certificate_t *cert = *in; + public_key_t *public; + + public = cert->get_public_key(cert); + if (!public) + { + return FALSE; + } + if (data->key != KEY_ANY && public->get_type(public) != data->key) + { + public->destroy(public); + return FALSE; + } + if (data->id && data->id->get_type(data->id) == ID_KEY_ID && + public->has_fingerprint(public, data->id->get_encoding(data->id))) + { + public->destroy(public); + *out = cert; + return TRUE; + } + public->destroy(public); + if (data->id && !cert->has_subject(cert, data->id)) + { + return FALSE; + } + *out = cert; + return TRUE; +} + +/** + * Create enumerator for trusted certificates + */ +static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this, + key_type_t key, identification_t *id) +{ + cert_data_t *data; + + INIT(data, + .this = this, + .id = id, + .key = key, + ); + + this->lock->read_lock(this->lock); + return enumerator_create_filter( + this->certs->create_enumerator(this->certs), + (void*)cert_filter, data, (void*)cert_data_destroy); +} + +METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, + private_nm_creds_t *this, certificate_type_t cert, key_type_t key, + identification_t *id, bool trusted) +{ + if (id && this->usercert && + id->equals(id, this->usercert->get_subject(this->usercert))) + { + return create_usercert_enumerator(this, cert, key); + } + if (cert == CERT_X509 || cert == CERT_ANY) + { + return create_trusted_cert_enumerator(this, key, id); + } + return NULL; +} + +METHOD(credential_set_t, create_private_enumerator, enumerator_t*, + private_nm_creds_t *this, key_type_t type, identification_t *id) +{ + if (this->key == NULL) + { + return NULL; + } + if (type != KEY_ANY && type != this->key->get_type(this->key)) + { + return NULL; + } + if (id && id->get_type(id) != ID_ANY) + { + if (id->get_type(id) != ID_KEY_ID || + !this->key->has_fingerprint(this->key, id->get_encoding(id))) + { + return NULL; + } + } + this->lock->read_lock(this->lock); + return enumerator_create_cleaner(enumerator_create_single(this->key, NULL), + (void*)this->lock->unlock, this->lock); +} + +/** + * shared key enumerator implementation + */ +typedef struct { + enumerator_t public; + private_nm_creds_t *this; + shared_key_t *key; + bool done; +} shared_enumerator_t; + +METHOD(enumerator_t, shared_enumerate, bool, + shared_enumerator_t *this, shared_key_t **key, id_match_t *me, + id_match_t *other) +{ + if (this->done) + { + return FALSE; + } + *key = this->key; + if (me) + { + *me = ID_MATCH_PERFECT; + } + if (other) + { + *other = ID_MATCH_ANY; + } + this->done = TRUE; + return TRUE; +} + +METHOD(enumerator_t, shared_destroy, void, + shared_enumerator_t *this) +{ + this->key->destroy(this->key); + this->this->lock->unlock(this->this->lock); + free(this); +} + +METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, + private_nm_creds_t *this, shared_key_type_t type, identification_t *me, + identification_t *other) +{ + shared_enumerator_t *enumerator; + chunk_t key; + + this->lock->read_lock(this->lock); + + switch (type) + { + case SHARED_EAP: + case SHARED_IKE: + if (!this->pass || !this->user) + { + goto no_secret; + } + if (me && !me->equals(me, this->user)) + { + goto no_secret; + } + key = chunk_create(this->pass, strlen(this->pass)); + break; + case SHARED_PRIVATE_KEY_PASS: + if (!this->keypass) + { + goto no_secret; + } + key = chunk_create(this->keypass, strlen(this->keypass)); + break; + case SHARED_PIN: + if (!this->keypass || !me || + !chunk_equals(me->get_encoding(me), this->keyid)) + { + goto no_secret; + } + key = chunk_create(this->keypass, strlen(this->keypass)); + break; + default: + goto no_secret; + } + + INIT(enumerator, + .public = { + .enumerate = (void*)_shared_enumerate, + .destroy = _shared_destroy, + }, + .this = this, + ); + enumerator->key = shared_key_create(type, chunk_clone(key)); + return &enumerator->public; + +no_secret: + this->lock->unlock(this->lock); + return NULL; +} + +METHOD(nm_creds_t, add_certificate, void, + private_nm_creds_t *this, certificate_t *cert) +{ + this->lock->write_lock(this->lock); + this->certs->insert_last(this->certs, cert); + this->lock->unlock(this->lock); +} + +/** + * Load a certificate file + */ +static void load_ca_file(private_nm_creds_t *this, char *file) +{ + certificate_t *cert; + + /* We add the CA constraint, as many CAs miss it */ + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, file, BUILD_END); + if (!cert) + { + DBG1(DBG_CFG, "loading CA certificate '%s' failed", file); + } + else + { + DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert)); + x509_t *x509 = (x509_t*)cert; + if (!(x509->get_flags(x509) & X509_SELF_SIGNED)) + { + DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert)); + } + this->certs->insert_last(this->certs, cert); + } +} + +METHOD(nm_creds_t, load_ca_dir, void, + private_nm_creds_t *this, char *dir) +{ + enumerator_t *enumerator; + char *rel, *abs; + struct stat st; + + enumerator = enumerator_create_directory(dir); + if (enumerator) + { + while (enumerator->enumerate(enumerator, &rel, &abs, &st)) + { + /* skip '.', '..' and hidden files */ + if (rel[0] != '.') + { + if (S_ISDIR(st.st_mode)) + { + load_ca_dir(this, abs); + } + else if (S_ISREG(st.st_mode)) + { + load_ca_file(this, abs); + } + } + } + enumerator->destroy(enumerator); + } +} + +METHOD(nm_creds_t, set_username_password, void, + private_nm_creds_t *this, identification_t *id, char *password) +{ + this->lock->write_lock(this->lock); + DESTROY_IF(this->user); + this->user = id->clone(id); + free(this->pass); + this->pass = strdupnull(password); + this->lock->unlock(this->lock); +} + +METHOD(nm_creds_t, set_key_password, void, + private_nm_creds_t *this, char *password) +{ + this->lock->write_lock(this->lock); + free(this->keypass); + this->keypass = strdupnull(password); + this->lock->unlock(this->lock); +} + +METHOD(nm_creds_t, set_pin, void, + private_nm_creds_t *this, chunk_t keyid, char *pin) +{ + this->lock->write_lock(this->lock); + free(this->keypass); + free(this->keyid.ptr); + this->keypass = strdupnull(pin); + this->keyid = chunk_clone(keyid); + this->lock->unlock(this->lock); +} + +METHOD(nm_creds_t, set_cert_and_key, void, + private_nm_creds_t *this, certificate_t *cert, private_key_t *key) +{ + this->lock->write_lock(this->lock); + DESTROY_IF(this->key); + DESTROY_IF(this->usercert); + this->key = key; + this->usercert = cert; + this->lock->unlock(this->lock); +} + +METHOD(nm_creds_t, clear, void, + private_nm_creds_t *this) +{ + certificate_t *cert; + + while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS) + { + cert->destroy(cert); + } + DESTROY_IF(this->user); + free(this->pass); + free(this->keypass); + free(this->keyid.ptr); + DESTROY_IF(this->usercert); + DESTROY_IF(this->key); + this->key = NULL; + this->usercert = NULL; + this->pass = NULL; + this->user = NULL; + this->keypass = NULL; + this->keyid = chunk_empty; +} + +METHOD(nm_creds_t, destroy, void, + private_nm_creds_t *this) +{ + clear(this); + this->certs->destroy(this->certs); + this->lock->destroy(this->lock); + free(this); +} + +/* + * see header file + */ +nm_creds_t *nm_creds_create() +{ + private_nm_creds_t *this; + + INIT(this, + .public = { + .set = { + .create_private_enumerator = _create_private_enumerator, + .create_cert_enumerator = _create_cert_enumerator, + .create_shared_enumerator = _create_shared_enumerator, + .create_cdp_enumerator = (void*)return_null, + .cache_cert = (void*)nop, + }, + .add_certificate = _add_certificate, + .load_ca_dir = _load_ca_dir, + .set_username_password = _set_username_password, + .set_key_password = _set_key_password, + .set_pin = _set_pin, + .set_cert_and_key = _set_cert_and_key, + .clear = _clear, + .destroy = _destroy, + }, + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .certs = linked_list_create(), + ); + return &this->public; +} + diff --git a/src/charon-nm/nm/nm_creds.h b/src/charon-nm/nm/nm_creds.h new file mode 100644 index 000000000..91f645c7e --- /dev/null +++ b/src/charon-nm/nm/nm_creds.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nm_creds nm_creds + * @{ @ingroup nm + */ + +#ifndef NM_CREDS_H_ +#define NM_CREDS_H_ + +#include +#include + +typedef struct nm_creds_t nm_creds_t; + +/** + * NetworkManager credentials helper. + */ +struct nm_creds_t { + + /** + * Implements credential_set_t + */ + credential_set_t set; + + /** + * Add a trusted gateway certificate to serve by this set. + * + * @param cert certificate to serve + */ + void (*add_certificate)(nm_creds_t *this, certificate_t *cert); + + /** + * Load CA certificates recursively from a directory. + * + * @param dir directory to PEM encoded CA certificates + */ + void (*load_ca_dir)(nm_creds_t *this, char *dir); + + /** + * Set the username/password for authentication. + * + * @param id ID of the user + * @param password password to use for authentication + */ + void (*set_username_password)(nm_creds_t *this, identification_t *id, + char *password); + + /** + * Set the passphrase to use for private key decryption. + * + * @param password password to use + */ + void (*set_key_password)(nm_creds_t *this, char *password); + + /** + * Set the PIN to unlock a smartcard. + * + * @param keyid keyid of the smartcard key + * @param pin PIN + */ + void (*set_pin)(nm_creds_t *this, chunk_t keyid, char *pin); + + /** + * Set the certificate and private key to use for client authentication. + * + * @param cert client certificate + * @param key associated private key + */ + void (*set_cert_and_key)(nm_creds_t *this, certificate_t *cert, + private_key_t *key); + + /** + * Clear the stored credentials. + */ + void (*clear)(nm_creds_t *this); + + /** + * Destroy a nm_creds instance. + */ + void (*destroy)(nm_creds_t *this); +}; + +/** + * Create a nm_creds instance. + */ +nm_creds_t *nm_creds_create(); + +#endif /** NM_CREDS_H_ @}*/ diff --git a/src/charon-nm/nm/nm_handler.c b/src/charon-nm/nm/nm_handler.c new file mode 100644 index 000000000..28aa04b31 --- /dev/null +++ b/src/charon-nm/nm/nm_handler.c @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "nm_handler.h" + +#include + +typedef struct private_nm_handler_t private_nm_handler_t; + +/** + * Private data of an nm_handler_t object. + */ +struct private_nm_handler_t { + + /** + * Public nm_handler_t interface. + */ + nm_handler_t public; + + /** + * list of received DNS server attributes, pointer to 4 byte data + */ + linked_list_t *dns; + + /** + * list of received NBNS server attributes, pointer to 4 byte data + */ + linked_list_t *nbns; +}; + +METHOD(attribute_handler_t, handle, bool, + private_nm_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + linked_list_t *list; + + switch (type) + { + case INTERNAL_IP4_DNS: + list = this->dns; + break; + case INTERNAL_IP4_NBNS: + list = this->nbns; + break; + default: + return FALSE; + } + if (data.len != 4) + { + return FALSE; + } + list->insert_last(list, chunk_clone(data).ptr); + return TRUE; +} + +/** + * Implementation of create_attribute_enumerator().enumerate() for WINS + */ +static bool enumerate_nbns(enumerator_t *this, + configuration_attribute_type_t *type, chunk_t *data) +{ + *type = INTERNAL_IP4_NBNS; + *data = chunk_empty; + /* done */ + this->enumerate = (void*)return_false; + return TRUE; +} + +/** + * Implementation of create_attribute_enumerator().enumerate() for DNS + */ +static bool enumerate_dns(enumerator_t *this, + configuration_attribute_type_t *type, chunk_t *data) +{ + *type = INTERNAL_IP4_DNS; + *data = chunk_empty; + /* enumerate WINS server as next attribute ... */ + this->enumerate = (void*)enumerate_nbns; + return TRUE; +} + +METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, + private_nm_handler_t *this, identification_t *server, linked_list_t *vips) +{ + if (vips->get_count(vips)) + { + enumerator_t *enumerator; + + INIT(enumerator, + /* enumerate DNS attribute first ... */ + .enumerate = (void*)enumerate_dns, + .destroy = (void*)free, + ); + return enumerator; + } + return enumerator_create_empty(); +} + +/** + * convert plain byte ptrs to handy chunk during enumeration + */ +static bool filter_chunks(void* null, char **in, chunk_t *out) +{ + *out = chunk_create(*in, 4); + return TRUE; +} + +METHOD(nm_handler_t, create_enumerator, enumerator_t*, + private_nm_handler_t *this, configuration_attribute_type_t type) +{ + linked_list_t *list; + + switch (type) + { + case INTERNAL_IP4_DNS: + list = this->dns; + break; + case INTERNAL_IP4_NBNS: + list = this->nbns; + break; + default: + return enumerator_create_empty(); + } + return enumerator_create_filter(list->create_enumerator(list), + (void*)filter_chunks, NULL, NULL); +} + +METHOD(nm_handler_t, reset, void, + private_nm_handler_t *this) +{ + void *data; + + while (this->dns->remove_last(this->dns, (void**)&data) == SUCCESS) + { + free(data); + } + while (this->nbns->remove_last(this->nbns, (void**)&data) == SUCCESS) + { + free(data); + } +} + +METHOD(nm_handler_t, destroy, void, + private_nm_handler_t *this) +{ + reset(this); + this->dns->destroy(this->dns); + this->nbns->destroy(this->nbns); + free(this); +} + +/** + * See header + */ +nm_handler_t *nm_handler_create() +{ + private_nm_handler_t *this; + + INIT(this, + .public = { + .handler = { + .handle = _handle, + .release = nop, + .create_attribute_enumerator = _create_attribute_enumerator, + }, + .create_enumerator = _create_enumerator, + .reset = _reset, + .destroy = _destroy, + }, + .dns = linked_list_create(), + .nbns = linked_list_create(), + ); + + return &this->public; +} + diff --git a/src/charon-nm/nm/nm_handler.h b/src/charon-nm/nm/nm_handler.h new file mode 100644 index 000000000..bb35ce767 --- /dev/null +++ b/src/charon-nm/nm/nm_handler.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nm_handler nm_handler + * @{ @ingroup nm + */ + +#ifndef NM_HANDLER_H_ +#define NM_HANDLER_H_ + +#include + +typedef struct nm_handler_t nm_handler_t; + +/** + * Handles DNS/NBNS attributes to pass to NM. + */ +struct nm_handler_t { + + /** + * Implements attribute handler interface + */ + attribute_handler_t handler; + + /** + * Create an enumerator over received attributes of a given kind. + * + * @param type type of attributes to enumerate + * @return enumerator over attribute data (chunk_t) + */ + enumerator_t* (*create_enumerator)(nm_handler_t *this, + configuration_attribute_type_t type); + /** + * Reset state, flush all received attributes. + */ + void (*reset)(nm_handler_t *this); + + /** + * Destroy a nm_handler_t. + */ + void (*destroy)(nm_handler_t *this); +}; + +/** + * Create a nm_handler instance. + */ +nm_handler_t *nm_handler_create(); + +#endif /** NM_HANDLER_H_ @}*/ diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c new file mode 100644 index 000000000..b7155b44b --- /dev/null +++ b/src/charon-nm/nm/nm_service.c @@ -0,0 +1,720 @@ +/* + * Copyright (C) 2008-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include "nm_service.h" + +#include +#include +#include +#include +#include + +#include + +G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_PLUGIN) + +/** + * Private data of NMStrongswanPlugin + */ +typedef struct { + /* implements bus listener interface */ + listener_t listener; + /* IKE_SA we are listening on */ + ike_sa_t *ike_sa; + /* backref to public plugin */ + NMVPNPlugin *plugin; + /* credentials to use for authentication */ + nm_creds_t *creds; + /* attribute handler for DNS/NBNS server information */ + nm_handler_t *handler; + /* name of the connection */ + char *name; +} NMStrongswanPluginPrivate; + +#define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate)) + +/** + * convert enumerated handler chunks to a UINT_ARRAY GValue + */ +static GValue* handler_to_val(nm_handler_t *handler, + configuration_attribute_type_t type) +{ + GValue *val; + GArray *array; + enumerator_t *enumerator; + chunk_t chunk; + + enumerator = handler->create_enumerator(handler, type); + array = g_array_new (FALSE, TRUE, sizeof (guint32)); + while (enumerator->enumerate(enumerator, &chunk)) + { + g_array_append_val (array, *(u_int32_t*)chunk.ptr); + } + enumerator->destroy(enumerator); + val = g_slice_new0 (GValue); + g_value_init (val, DBUS_TYPE_G_UINT_ARRAY); + g_value_set_boxed (val, array); + + return val; +} + +/** + * signal IPv4 config to NM, set connection as established + */ +static void signal_ipv4_config(NMVPNPlugin *plugin, + ike_sa_t *ike_sa, child_sa_t *child_sa) +{ + GValue *val; + GHashTable *config; + host_t *me; + nm_handler_t *handler; + + config = g_hash_table_new(g_str_hash, g_str_equal); + me = ike_sa->get_my_host(ike_sa); + handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler; + + /* NM requires a tundev, but netkey does not use one. Passing the physical + * interface does not work, as NM fiddles around with it. Passing the + * loopback seems to work, though... */ + val = g_slice_new0 (GValue); + g_value_init (val, G_TYPE_STRING); + g_value_set_string (val, "lo"); + g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, val); + + val = g_slice_new0(GValue); + g_value_init(val, G_TYPE_UINT); + g_value_set_uint(val, *(u_int32_t*)me->get_address(me).ptr); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val); + + val = g_slice_new0(GValue); + g_value_init(val, G_TYPE_UINT); + g_value_set_uint(val, me->get_address(me).len * 8); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); + + val = handler_to_val(handler, INTERNAL_IP4_DNS); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val); + + val = handler_to_val(handler, INTERNAL_IP4_NBNS); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val); + + handler->reset(handler); + + nm_vpn_plugin_set_ip4_config(plugin, config); +} + +/** + * signal failure to NM, connecting failed + */ +static void signal_failure(NMVPNPlugin *plugin, NMVPNPluginFailure failure) +{ + nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler; + + handler->reset(handler); + + /* TODO: NM does not handle this failure!? */ + nm_vpn_plugin_failure(plugin, failure); + nm_vpn_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STOPPED); +} + +/** + * Implementation of listener_t.ike_state_change + */ +static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa, + ike_sa_state_t state) +{ + NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; + + if (private->ike_sa == ike_sa && state == IKE_DESTROYING) + { + signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED); + return FALSE; + } + return TRUE; +} + +/** + * Implementation of listener_t.child_state_change + */ +static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa, + child_sa_t *child_sa, child_sa_state_t state) +{ + NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; + + if (private->ike_sa == ike_sa && state == CHILD_DESTROYING) + { + signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); + return FALSE; + } + return TRUE; +} + +/** + * Implementation of listener_t.child_updown + */ +static bool child_updown(listener_t *listener, ike_sa_t *ike_sa, + child_sa_t *child_sa, bool up) +{ + NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; + + if (private->ike_sa == ike_sa) + { + if (up) + { /* disable initiate-failure-detection hooks */ + private->listener.ike_state_change = NULL; + private->listener.child_state_change = NULL; + signal_ipv4_config(private->plugin, ike_sa, child_sa); + } + else + { + signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); + return FALSE; + } + } + return TRUE; +} + +/** + * Implementation of listener_t.ike_rekey + */ +static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new) +{ + NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; + + if (private->ike_sa == old) + { /* follow a rekeyed IKE_SA */ + private->ike_sa = new; + } + return TRUE; +} + +/** + * Find a certificate for which we have a private key on a smartcard + */ +static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv, + char *pin) +{ + enumerator_t *enumerator, *sans; + identification_t *id = NULL; + certificate_t *cert; + x509_t *x509; + private_key_t *key; + chunk_t keyid; + + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_X509, KEY_ANY, NULL, FALSE); + while (enumerator->enumerate(enumerator, &cert)) + { + x509 = (x509_t*)cert; + + /* there might be a lot of certificates, filter them by usage */ + if ((x509->get_flags(x509) & X509_CLIENT_AUTH) && + !(x509->get_flags(x509) & X509_CA)) + { + keyid = x509->get_subjectKeyIdentifier(x509); + if (keyid.ptr) + { + /* try to find a private key by the certificate keyid */ + priv->creds->set_pin(priv->creds, keyid, pin); + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END); + if (key) + { + /* prefer a more convenient subjectAltName */ + sans = x509->create_subjectAltName_enumerator(x509); + if (!sans->enumerate(sans, &id)) + { + id = cert->get_subject(cert); + } + id = id->clone(id); + sans->destroy(sans); + + DBG1(DBG_CFG, "using smartcard certificate '%Y'", id); + priv->creds->set_cert_and_key(priv->creds, + cert->get_ref(cert), key); + break; + } + } + } + } + enumerator->destroy(enumerator); + return id; +} + +/** + * Connect function called from NM via DBUS + */ +static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, + GError **err) +{ + NMStrongswanPluginPrivate *priv; + NMSettingConnection *conn; + NMSettingVPN *vpn; + identification_t *user = NULL, *gateway = NULL; + const char *address, *str; + bool virtual, encap, ipcomp; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + traffic_selector_t *ts; + ike_sa_t *ike_sa; + auth_cfg_t *auth; + auth_class_t auth_class = AUTH_CLASS_EAP; + certificate_t *cert = NULL; + x509_t *x509; + bool agent = FALSE, smartcard = FALSE, loose_gateway_id = FALSE; + lifetime_cfg_t lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + } + }; + + /** + * Read parameters + */ + priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); + conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection, + NM_TYPE_SETTING_CONNECTION)); + vpn = NM_SETTING_VPN(nm_connection_get_setting(connection, + NM_TYPE_SETTING_VPN)); + if (priv->name) + { + free(priv->name); + } + priv->name = strdup(nm_setting_connection_get_id(conn)); + DBG1(DBG_CFG, "received initiate for NetworkManager connection %s", + priv->name); + DBG4(DBG_CFG, "%s", + nm_setting_to_string(NM_SETTING(vpn))); + address = nm_setting_vpn_get_data_item(vpn, "address"); + if (!address || !*address) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Gateway address missing."); + return FALSE; + } + str = nm_setting_vpn_get_data_item(vpn, "virtual"); + virtual = str && streq(str, "yes"); + str = nm_setting_vpn_get_data_item(vpn, "encap"); + encap = str && streq(str, "yes"); + str = nm_setting_vpn_get_data_item(vpn, "ipcomp"); + ipcomp = str && streq(str, "yes"); + str = nm_setting_vpn_get_data_item(vpn, "method"); + if (str) + { + if (streq(str, "psk")) + { + auth_class = AUTH_CLASS_PSK; + } + else if (streq(str, "agent")) + { + auth_class = AUTH_CLASS_PUBKEY; + agent = TRUE; + } + else if (streq(str, "key")) + { + auth_class = AUTH_CLASS_PUBKEY; + } + else if (streq(str, "smartcard")) + { + auth_class = AUTH_CLASS_PUBKEY; + smartcard = TRUE; + } + } + + /** + * Register credentials + */ + priv->creds->clear(priv->creds); + + /* gateway/CA cert */ + str = nm_setting_vpn_get_data_item(vpn, "certificate"); + if (str) + { + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, str, BUILD_END); + if (!cert) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Loading gateway certificate failed."); + return FALSE; + } + priv->creds->add_certificate(priv->creds, cert); + + x509 = (x509_t*)cert; + if (!(x509->get_flags(x509) & X509_CA)) + { /* For a gateway certificate, we use the cert subject as identity. */ + gateway = cert->get_subject(cert); + gateway = gateway->clone(gateway); + DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway); + } + } + else + { + /* no certificate defined, fall back to system-wide CA certificates */ + priv->creds->load_ca_dir(priv->creds, NM_CA_DIR); + } + if (!gateway) + { + /* If the user configured a CA certificate, we use the IP/DNS + * of the gateway as its identity. This identity will be used for + * certificate lookup and requires the configured IP/DNS to be + * included in the gateway certificate. */ + gateway = identification_create_from_string((char*)address); + DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway); + loose_gateway_id = TRUE; + } + + if (auth_class == AUTH_CLASS_EAP) + { + /* username/password authentication ... */ + str = nm_setting_vpn_get_data_item(vpn, "user"); + if (str) + { + user = identification_create_from_string((char*)str); + str = nm_setting_vpn_get_secret(vpn, "password"); + priv->creds->set_username_password(priv->creds, user, (char*)str); + } + } + + if (auth_class == AUTH_CLASS_PUBKEY) + { + if (smartcard) + { + char *pin; + + pin = (char*)nm_setting_vpn_get_secret(vpn, "password"); + if (pin) + { + user = find_smartcard_key(priv, pin); + } + if (!user) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "no usable smartcard certificate found."); + gateway->destroy(gateway); + return FALSE; + } + } + /* ... or certificate/private key authenitcation */ + else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert"))) + { + public_key_t *public; + private_key_t *private = NULL; + + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, str, BUILD_END); + if (!cert) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Loading peer certificate failed."); + gateway->destroy(gateway); + return FALSE; + } + /* try agent */ + str = nm_setting_vpn_get_secret(vpn, "agent"); + if (agent && str) + { + public = cert->get_public_key(cert); + if (public) + { + private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + public->get_type(public), + BUILD_AGENT_SOCKET, str, + BUILD_PUBLIC_KEY, public, + BUILD_END); + public->destroy(public); + } + if (!private) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Connecting to SSH agent failed."); + } + } + /* ... or key file */ + str = nm_setting_vpn_get_data_item(vpn, "userkey"); + if (!agent && str) + { + char *secret; + + secret = (char*)nm_setting_vpn_get_secret(vpn, "password"); + if (secret) + { + priv->creds->set_key_password(priv->creds, secret); + } + private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + KEY_RSA, BUILD_FROM_FILE, str, BUILD_END); + if (!private) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Loading private key failed."); + } + } + if (private) + { + user = cert->get_subject(cert); + user = user->clone(user); + priv->creds->set_cert_and_key(priv->creds, cert, private); + } + else + { + DESTROY_IF(cert); + gateway->destroy(gateway); + return FALSE; + } + } + } + + if (!user) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Configuration parameters missing."); + gateway->destroy(gateway); + return FALSE; + } + + /** + * Set up configurations + */ + ike_cfg = ike_cfg_create(TRUE, encap, "0.0.0.0", FALSE, + charon->socket->get_port(charon->socket, FALSE), + (char*)address, FALSE, IKEV2_UDP_PORT); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + peer_cfg = peer_cfg_create(priv->name, IKEV2, ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ + 36000, 0, /* rekey 10h, reauth none */ + 600, 600, /* jitter, over 10min */ + TRUE, FALSE, /* mobike, aggressive */ + 0, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + if (virtual) + { + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); + } + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class); + auth->add(auth, AUTH_RULE_IDENTITY, user); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, gateway); + auth->add(auth, AUTH_RULE_IDENTITY_LOOSE, loose_gateway_id); + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); + + child_cfg = child_cfg_create(priv->name, &lifetime, + NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */ + ACTION_NONE, ACTION_NONE, ACTION_NONE, ipcomp, + 0, 0, NULL, NULL, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + ts = traffic_selector_create_dynamic(0, 0, 65535); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, + "255.255.255.255", 65535); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + + /** + * Prepare IKE_SA + */ + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, + "IKE version not supported."); + return FALSE; + } + if (!ike_sa->get_peer_cfg(ike_sa)) + { + ike_sa->set_peer_cfg(ike_sa, peer_cfg); + } + peer_cfg->destroy(peer_cfg); + + /** + * Register listener, enable initiate-failure-detection hooks + */ + priv->ike_sa = ike_sa; + priv->listener.ike_state_change = ike_state_change; + priv->listener.child_state_change = child_state_change; + charon->bus->add_listener(charon->bus, &priv->listener); + + /** + * Initiate + */ + child_cfg->get_ref(child_cfg); + if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) + { + charon->bus->remove_listener(charon->bus, &priv->listener); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, + "Initiating failed."); + return FALSE; + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return TRUE; +} + +/** + * NeedSecrets called from NM via DBUS + */ +static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, + char **setting_name, GError **error) +{ + NMSettingVPN *settings; + const char *method, *path; + + settings = NM_SETTING_VPN(nm_connection_get_setting(connection, + NM_TYPE_SETTING_VPN)); + method = nm_setting_vpn_get_data_item(settings, "method"); + if (method) + { + if (streq(method, "eap")) + { + if (nm_setting_vpn_get_secret(settings, "password")) + { + return FALSE; + } + } + else if (streq(method, "agent")) + { + if (nm_setting_vpn_get_secret(settings, "agent")) + { + return FALSE; + } + } + else if (streq(method, "key")) + { + path = nm_setting_vpn_get_data_item(settings, "userkey"); + if (path) + { + private_key_t *key; + + /* try to load/decrypt the private key */ + key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, + KEY_RSA, BUILD_FROM_FILE, path, BUILD_END); + if (key) + { + key->destroy(key); + return FALSE; + } + } + } + else if (streq(method, "smartcard")) + { + if (nm_setting_vpn_get_secret(settings, "password")) + { + return FALSE; + } + } + } + *setting_name = NM_SETTING_VPN_SETTING_NAME; + return TRUE; +} + +/** + * Disconnect called from NM via DBUS + */ +static gboolean disconnect(NMVPNPlugin *plugin, GError **err) +{ + NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); + enumerator_t *enumerator; + ike_sa_t *ike_sa; + u_int id; + + /* our ike_sa pointer might be invalid, lookup sa */ + enumerator = charon->controller->create_ike_sa_enumerator( + charon->controller, TRUE); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + if (priv->ike_sa == ike_sa) + { + id = ike_sa->get_unique_id(ike_sa); + enumerator->destroy(enumerator); + charon->controller->terminate_ike(charon->controller, id, + controller_cb_empty, NULL, 0); + return TRUE; + } + } + enumerator->destroy(enumerator); + + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_GENERAL, + "Connection not found."); + return FALSE; +} + +/** + * Initializer + */ +static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin) +{ + NMStrongswanPluginPrivate *priv; + + priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); + priv->plugin = NM_VPN_PLUGIN(plugin); + memset(&priv->listener, 0, sizeof(listener_t)); + priv->listener.child_updown = child_updown; + priv->listener.ike_rekey = ike_rekey; +} + +/** + * Class constructor + */ +static void nm_strongswan_plugin_class_init( + NMStrongswanPluginClass *strongswan_class) +{ + NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS(strongswan_class); + + g_type_class_add_private(G_OBJECT_CLASS(strongswan_class), + sizeof(NMStrongswanPluginPrivate)); + parent_class->connect = connect_; + parent_class->need_secrets = need_secrets; + parent_class->disconnect = disconnect; +} + +/** + * Object constructor + */ +NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds, + nm_handler_t *handler) +{ + NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_object_new ( + NM_TYPE_STRONGSWAN_PLUGIN, + NM_VPN_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN, + NULL); + if (plugin) + { + NMStrongswanPluginPrivate *priv; + + priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); + priv->creds = creds; + priv->handler = handler; + priv->name = NULL; + } + return plugin; +} + diff --git a/src/charon-nm/nm/nm_service.h b/src/charon-nm/nm/nm_service.h new file mode 100644 index 000000000..828d1a452 --- /dev/null +++ b/src/charon-nm/nm/nm_service.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nm_service nm_service + * @{ @ingroup nm + */ + +#ifndef NM_SERVICE_H_ +#define NM_SERVICE_H_ + +#include +#include +#include + +#include "nm_creds.h" +#include "nm_handler.h" + +#define NM_TYPE_STRONGSWAN_PLUGIN (nm_strongswan_plugin_get_type ()) +#define NM_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPlugin)) +#define NM_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) +#define NM_IS_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) +#define NM_IS_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) +#define NM_STRONGSWAN_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) + +#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_INTERFACE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_PATH_STRONGSWAN "/org/freedesktop/NetworkManager/strongswan" + +typedef struct { + NMVPNPlugin parent; +} NMStrongswanPlugin; + +typedef struct { + NMVPNPluginClass parent; +} NMStrongswanPluginClass; + +GType nm_strongswan_plugin_get_type(void); + +NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds, + nm_handler_t *handler); + +#endif /** NM_SERVICE_H_ @}*/ diff --git a/src/charon/Android.mk b/src/charon/Android.mk index eb7eca9dd..1dd27d534 100644 --- a/src/charon/Android.mk +++ b/src/charon/Android.mk @@ -13,7 +13,8 @@ LOCAL_C_INCLUDES += \ $(strongswan_PATH)/src/libcharon \ $(strongswan_PATH)/src/libstrongswan -LOCAL_CFLAGS := $(strongswan_CFLAGS) +LOCAL_CFLAGS := $(strongswan_CFLAGS) \ + -DPLUGINS='"$(strongswan_CHARON_PLUGINS)"' LOCAL_MODULE := charon diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 6481947f1..0ca15cb10 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -3,6 +3,8 @@ ipsec_PROGRAMS = charon charon_SOURCES = \ charon.c +charon.o : $(top_builddir)/config.status + INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ -I$(top_srcdir)/src/libhydra \ @@ -10,7 +12,8 @@ INCLUDES = \ AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_PIDDIR=\"${piddir}\" + -DIPSEC_PIDDIR=\"${piddir}\" \ + -DPLUGINS=\""${charon_plugins}\"" charon_LDADD = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in index 5da167dfd..d8109bb7f 100644 --- a/src/charon/Makefile.in +++ b/src/charon/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" @@ -62,7 +63,7 @@ charon_DEPENDENCIES = \ $(top_builddir)/src/libhydra/libhydra.la \ $(top_builddir)/src/libcharon/libcharon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -88,6 +89,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -182,11 +184,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -203,11 +208,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -223,6 +229,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -232,7 +239,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -270,7 +276,8 @@ INCLUDES = \ AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_PIDDIR=\"${piddir}\" + -DIPSEC_PIDDIR=\"${piddir}\" \ + -DPLUGINS=\""${charon_plugins}\"" charon_LDADD = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ @@ -597,6 +604,8 @@ uninstall-am: uninstall-ipsecPROGRAMS tags uninstall uninstall-am uninstall-ipsecPROGRAMS +charon.o : $(top_builddir)/config.status + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/charon/charon.c b/src/charon/charon.c index 6dbb0b592..bd36c72f4 100644 --- a/src/charon/charon.c +++ b/src/charon/charon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -17,21 +17,17 @@ */ #include -#ifdef HAVE_PRCTL -#include -#endif #define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */ #include #undef _POSIX_PTHREAD_SEMANTICS #include #include #include +#include #include #include #include #include -#include -#include #include #include @@ -142,68 +138,25 @@ static void run() } } -/** - * drop daemon capabilities - */ -static bool drop_capabilities() -{ -#ifdef HAVE_PRCTL - prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); -#endif - - if (setgid(charon->gid) != 0) - { - DBG1(DBG_DMN, "change to unprivileged group failed"); - return FALSE; - } - if (setuid(charon->uid) != 0) - { - DBG1(DBG_DMN, "change to unprivileged user failed"); - return FALSE; - } - if (!charon->drop_capabilities(charon)) - { - DBG1(DBG_DMN, "unable to drop daemon capabilities"); - return FALSE; - } - return TRUE; -} - /** * lookup UID and GID */ static bool lookup_uid_gid() { #ifdef IPSEC_USER + if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) { - char buf[1024]; - struct passwd passwd, *pwp; - - if (getpwnam_r(IPSEC_USER, &passwd, buf, sizeof(buf), &pwp) != 0 || - pwp == NULL) - { - DBG1(DBG_DMN, "resolving user '"IPSEC_USER"' failed"); - return FALSE; - } - charon->uid = pwp->pw_uid; + return FALSE; } #endif #ifdef IPSEC_GROUP + if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) { - char buf[1024]; - struct group group, *grp; - - if (getgrnam_r(IPSEC_GROUP, &group, buf, sizeof(buf), &grp) != 0 || - grp == NULL) - { - DBG1(DBG_DMN, "resolving group '"IPSEC_GROUP"' failed"); - return FALSE; - } - charon->gid = grp->gr_gid; + return FALSE; } #endif #ifdef ANDROID - charon->uid = AID_VPN; + charon->caps->set_uid(charon->caps, AID_VPN); #endif return TRUE; } @@ -259,7 +212,9 @@ static bool check_pidfile() pidfile = fopen(PID_FILE, "w"); if (pidfile) { - ignore_result(fchown(fileno(pidfile), charon->uid, charon->gid)); + ignore_result(fchown(fileno(pidfile), + charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps))); fprintf(pidfile, "%d\n", getpid()); fflush(pidfile); } @@ -335,7 +290,7 @@ static void initialize_loggers(bool use_stderr, level_t levels[]) facility, debug_lower_names, group)); } charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger); - charon->bus->add_listener(charon->bus, &sys_logger->listener); + charon->bus->add_logger(charon->bus, &sys_logger->logger); } enumerator->destroy(enumerator); @@ -385,7 +340,7 @@ static void initialize_loggers(bool use_stderr, level_t levels[]) filename, debug_lower_names, group)); } charon->file_loggers->insert_last(charon->file_loggers, file_logger); - charon->bus->add_listener(charon->bus, &file_logger->listener); + charon->bus->add_logger(charon->bus, &file_logger->logger); } enumerator->destroy(enumerator); @@ -395,11 +350,9 @@ static void initialize_loggers(bool use_stderr, level_t levels[]) { /* set up default stdout file_logger */ file_logger = file_logger_create(stdout, NULL, FALSE); - charon->bus->add_listener(charon->bus, &file_logger->listener); charon->file_loggers->insert_last(charon->file_loggers, file_logger); /* set up default daemon sys_logger */ sys_logger = sys_logger_create(LOG_DAEMON, FALSE); - charon->bus->add_listener(charon->bus, &sys_logger->listener); charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger); for (group = 0; group < DBG_MAX; group++) { @@ -409,12 +362,14 @@ static void initialize_loggers(bool use_stderr, level_t levels[]) file_logger->set_level(file_logger, group, levels[group]); } } + charon->bus->add_logger(charon->bus, &file_logger->logger); + charon->bus->add_logger(charon->bus, &sys_logger->logger); /* set up default auth sys_logger */ sys_logger = sys_logger_create(LOG_AUTHPRIV, FALSE); - charon->bus->add_listener(charon->bus, &sys_logger->listener); - charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger); sys_logger->set_level(sys_logger, DBG_ANY, LEVEL_AUDIT); + charon->sys_loggers->insert_last(charon->sys_loggers, sys_logger); + charon->bus->add_logger(charon->bus, &sys_logger->logger); } } @@ -432,7 +387,7 @@ static void usage(const char *msg) " [--version]\n" " [--use-syslog]\n" " [--debug- ]\n" - " : log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|lib)\n" + " : log context type (dmn|mgr|ike|chd|job|cfg|knl|net|asn|enc|tnc|imc|imv|pts|tls|esp|lib)\n" " : log verbosity (-1 = silent, 0 = audit, 1 = control,\n" " 2 = controlmore, 3 = raw, 4 = private)\n" "\n" @@ -448,6 +403,7 @@ int main(int argc, char *argv[]) bool use_syslog = FALSE; level_t levels[DBG_MAX]; int group, status = SS_RC_INITIALIZATION_FAILED; + struct utsname utsname; /* logging for library during initialization, as we have no bus yet */ dbg = dbg_stderr; @@ -475,7 +431,7 @@ int main(int argc, char *argv[]) exit(SS_RC_INITIALIZATION_FAILED); } - if (!libcharon_init()) + if (!libcharon_init("charon")) { dbg_stderr(DBG_DMN, 1, "initialization failed - aborting charon"); goto deinit; @@ -510,6 +466,7 @@ int main(int argc, char *argv[]) { "debug-imv", required_argument, &group, DBG_IMV }, { "debug-pts", required_argument, &group, DBG_PTS }, { "debug-tls", required_argument, &group, DBG_TLS }, + { "debug-esp", required_argument, &group, DBG_ESP }, { "debug-lib", required_argument, &group, DBG_LIB }, { 0,0,0,0 } }; @@ -550,8 +507,24 @@ int main(int argc, char *argv[]) initialize_loggers(!use_syslog, levels); + if (uname(&utsname) != 0) + { + memset(&utsname, 0, sizeof(utsname)); + } + DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)", + utsname.sysname, utsname.release, utsname.machine); + if (lib->integrity) + { + DBG1(DBG_DMN, "integrity tests enabled:"); + DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); + DBG1(DBG_DMN, "lib 'libhydra': passed file and segment integrity tests"); + DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); + DBG1(DBG_DMN, "daemon 'charon': passed file integrity test"); + } + /* initialize daemon */ - if (!charon->initialize(charon)) + if (!charon->initialize(charon, + lib->settings->get_str(lib->settings, "charon.load", PLUGINS))) { DBG1(DBG_DMN, "initialization failed - aborting charon"); goto deinit; @@ -564,7 +537,7 @@ int main(int argc, char *argv[]) goto deinit; } - if (!drop_capabilities()) + if (!charon->caps->drop(charon->caps)) { DBG1(DBG_DMN, "capability dropping failed - aborting charon"); goto deinit; diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am index 58292a45a..1405fcd05 100644 --- a/src/checksum/Makefile.am +++ b/src/checksum/Makefile.am @@ -40,6 +40,11 @@ if !MONOLITHIC endif endif +if USE_LIBIPSEC + deps += $(top_builddir)/src/libipsec/libipsec.la + libs += $(DESTDIR)$(ipseclibdir)/libipsec.so +endif + if USE_TLS deps += $(top_builddir)/src/libtls/libtls.la libs += $(DESTDIR)$(ipseclibdir)/libtls.so @@ -79,11 +84,6 @@ if !MONOLITHIC endif endif -if USE_PLUTO - exes += $(top_builddir)/src/pluto/.libs/pluto - AM_CFLAGS += -DP_PLUGINS=\""${p_plugins}\"" -endif - if USE_TOOLS exes += $(top_builddir)/src/openac/.libs/openac exes += $(top_builddir)/src/pki/.libs/pki diff --git a/src/checksum/Makefile.in b/src/checksum/Makefile.in index 8c89fc615..ecbc3ae39 100644 --- a/src/checksum/Makefile.in +++ b/src/checksum/Makefile.in @@ -40,24 +40,24 @@ noinst_PROGRAMS = checksum_builder$(EXEEXT) @USE_LIBHYDRA_TRUE@am__append_2 = $(top_builddir)/src/libhydra/libhydra.la @USE_LIBHYDRA_TRUE@am__append_3 = $(DESTDIR)$(ipseclibdir)/libhydra.so @MONOLITHIC_FALSE@@USE_LIBHYDRA_TRUE@am__append_4 = -DH_PLUGINS=\""${h_plugins}\"" -@USE_TLS_TRUE@am__append_5 = $(top_builddir)/src/libtls/libtls.la -@USE_TLS_TRUE@am__append_6 = $(DESTDIR)$(ipseclibdir)/libtls.so -@USE_RADIUS_TRUE@am__append_7 = $(top_builddir)/src/libradius/libradius.la -@USE_RADIUS_TRUE@am__append_8 = $(DESTDIR)$(ipseclibdir)/libradius.so -@USE_LIBTNCCS_TRUE@am__append_9 = $(top_builddir)/src/libtnccs/libtnccs.la -@USE_LIBTNCCS_TRUE@am__append_10 = $(DESTDIR)$(ipseclibdir)/libtnccs.so -@USE_SIMAKA_TRUE@am__append_11 = $(top_builddir)/src/libsimaka/libsimaka.la -@USE_SIMAKA_TRUE@am__append_12 = $(DESTDIR)$(ipseclibdir)/libsimaka.so -@USE_IMCV_TRUE@am__append_13 = $(top_builddir)/src/libimcv/libimcv.la -@USE_IMCV_TRUE@am__append_14 = $(DESTDIR)$(ipseclibdir)/libimcv.so -@USE_PTS_TRUE@am__append_15 = $(top_builddir)/src/libpts/libpts.la -@USE_PTS_TRUE@am__append_16 = $(DESTDIR)$(ipseclibdir)/libpts.so -@USE_CHARON_TRUE@am__append_17 = $(top_builddir)/src/libcharon/libcharon.la -@USE_CHARON_TRUE@am__append_18 = $(DESTDIR)$(ipseclibdir)/libcharon.so -@USE_CHARON_TRUE@am__append_19 = $(top_builddir)/src/charon/.libs/charon -@MONOLITHIC_FALSE@@USE_CHARON_TRUE@am__append_20 = -DC_PLUGINS=\""${c_plugins}\"" -@USE_PLUTO_TRUE@am__append_21 = $(top_builddir)/src/pluto/.libs/pluto -@USE_PLUTO_TRUE@am__append_22 = -DP_PLUGINS=\""${p_plugins}\"" +@USE_LIBIPSEC_TRUE@am__append_5 = $(top_builddir)/src/libipsec/libipsec.la +@USE_LIBIPSEC_TRUE@am__append_6 = $(DESTDIR)$(ipseclibdir)/libipsec.so +@USE_TLS_TRUE@am__append_7 = $(top_builddir)/src/libtls/libtls.la +@USE_TLS_TRUE@am__append_8 = $(DESTDIR)$(ipseclibdir)/libtls.so +@USE_RADIUS_TRUE@am__append_9 = $(top_builddir)/src/libradius/libradius.la +@USE_RADIUS_TRUE@am__append_10 = $(DESTDIR)$(ipseclibdir)/libradius.so +@USE_LIBTNCCS_TRUE@am__append_11 = $(top_builddir)/src/libtnccs/libtnccs.la +@USE_LIBTNCCS_TRUE@am__append_12 = $(DESTDIR)$(ipseclibdir)/libtnccs.so +@USE_SIMAKA_TRUE@am__append_13 = $(top_builddir)/src/libsimaka/libsimaka.la +@USE_SIMAKA_TRUE@am__append_14 = $(DESTDIR)$(ipseclibdir)/libsimaka.so +@USE_IMCV_TRUE@am__append_15 = $(top_builddir)/src/libimcv/libimcv.la +@USE_IMCV_TRUE@am__append_16 = $(DESTDIR)$(ipseclibdir)/libimcv.so +@USE_PTS_TRUE@am__append_17 = $(top_builddir)/src/libpts/libpts.la +@USE_PTS_TRUE@am__append_18 = $(DESTDIR)$(ipseclibdir)/libpts.so +@USE_CHARON_TRUE@am__append_19 = $(top_builddir)/src/libcharon/libcharon.la +@USE_CHARON_TRUE@am__append_20 = $(DESTDIR)$(ipseclibdir)/libcharon.so +@USE_CHARON_TRUE@am__append_21 = $(top_builddir)/src/charon/.libs/charon +@MONOLITHIC_FALSE@@USE_CHARON_TRUE@am__append_22 = -DC_PLUGINS=\""${c_plugins}\"" @USE_TOOLS_TRUE@am__append_23 = \ @USE_TOOLS_TRUE@ $(top_builddir)/src/openac/.libs/openac \ @USE_TOOLS_TRUE@ $(top_builddir)/src/pki/.libs/pki \ @@ -79,6 +79,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -119,7 +120,7 @@ checksum_builder_DEPENDENCIES = \ $(top_builddir)/src/libhydra/libhydra.la \ $(top_builddir)/src/libcharon/libcharon.la \ $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -145,6 +146,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -239,11 +241,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -260,11 +265,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -280,6 +286,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -289,7 +296,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -337,7 +343,7 @@ INCLUDES = \ -I$(top_srcdir)/src/libcharon AM_CFLAGS = -DPLUGINDIR=\"${plugindir}\" -rdynamic $(am__append_1) \ - $(am__append_4) $(am__append_20) $(am__append_22) + $(am__append_4) $(am__append_22) # we keep track of build dependencies in deps and use libs to store the paths # to the installed libraries. for executables we use the built files directly @@ -345,13 +351,13 @@ AM_CFLAGS = -DPLUGINDIR=\"${plugindir}\" -rdynamic $(am__append_1) \ deps = $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(am__append_2) $(am__append_5) $(am__append_7) \ $(am__append_9) $(am__append_11) $(am__append_13) \ - $(am__append_15) $(am__append_17) + $(am__append_15) $(am__append_17) $(am__append_19) libs = $(DESTDIR)$(ipseclibdir)/libstrongswan.so $(am__append_3) \ $(am__append_6) $(am__append_8) $(am__append_10) \ $(am__append_12) $(am__append_14) $(am__append_16) \ - $(am__append_18) -exes = $(am__append_19) $(am__append_21) $(am__append_23) \ - $(am__append_24) $(am__append_25) + $(am__append_18) $(am__append_20) +exes = $(am__append_21) $(am__append_23) $(am__append_24) \ + $(am__append_25) all: all-am .SUFFIXES: diff --git a/src/checksum/checksum_builder.c b/src/checksum/checksum_builder.c index 670ec76bd..b083d54db 100644 --- a/src/checksum/checksum_builder.c +++ b/src/checksum/checksum_builder.c @@ -106,14 +106,16 @@ static void build_binary_checksum(char *path) pos = strrchr(binary, '.'); if (pos && streq(pos, ".so")) { - snprintf(name, sizeof(name), "%.*s\",", pos - binary, binary); + snprintf(name, sizeof(name), "%.*s\",", (int)(pos - binary), + binary); if (streq(name, "libstrongswan\",")) { snprintf(sname, sizeof(sname), "%s", "library_init"); } else { - snprintf(sname, sizeof(sname), "%.*s_init", pos - binary, binary); + snprintf(sname, sizeof(sname), "%.*s_init", (int)(pos - binary), + binary); } build_checksum(path, name, sname); } diff --git a/src/conftest/Makefile.am b/src/conftest/Makefile.am index 7eab0df27..64a2cc6d3 100644 --- a/src/conftest/Makefile.am +++ b/src/conftest/Makefile.am @@ -1,6 +1,7 @@ ipsec_PROGRAMS = conftest -AM_CFLAGS = -rdynamic +AM_CFLAGS = -rdynamic \ + -DPLUGINS=\""${charon_plugins}\"" conftest_SOURCES = conftest.c conftest.h config.c config.h actions.c actions.h \ hooks/hook.h hooks/ike_auth_fill.c hooks/unsort_message.c \ diff --git a/src/conftest/Makefile.in b/src/conftest/Makefile.in index 4efdeaad5..ea26b70e7 100644 --- a/src/conftest/Makefile.in +++ b/src/conftest/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" @@ -73,7 +74,7 @@ conftest_DEPENDENCIES = \ $(top_builddir)/src/libhydra/libhydra.la \ $(top_builddir)/src/libcharon/libcharon.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -99,6 +100,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -193,11 +195,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -214,11 +219,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -234,6 +240,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -243,7 +250,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -271,7 +277,9 @@ top_srcdir = @top_srcdir@ urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ -AM_CFLAGS = -rdynamic +AM_CFLAGS = -rdynamic \ + -DPLUGINS=\""${charon_plugins}\"" + conftest_SOURCES = conftest.c conftest.h config.c config.h actions.c actions.h \ hooks/hook.h hooks/ike_auth_fill.c hooks/unsort_message.c \ hooks/add_notify.c hooks/unencrypted_notify.c hooks/ignore_message.c \ diff --git a/src/conftest/config.c b/src/conftest/config.c index 952141211..cbc6ac05f 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -103,9 +103,9 @@ static ike_cfg_t *load_ike_config(private_config_t *this, ike_cfg = ike_cfg_create(TRUE, settings->get_bool(settings, "configs.%s.fake_nat", FALSE, config), - settings->get_str(settings, "configs.%s.lhost", "%any", config), + settings->get_str(settings, "configs.%s.lhost", "%any", config), FALSE, settings->get_int(settings, "configs.%s.lport", 500, config), - settings->get_str(settings, "configs.%s.rhost", "%any", config), + settings->get_str(settings, "configs.%s.rhost", "%any", config), FALSE, settings->get_int(settings, "configs.%s.rport", 500, config)); token = settings->get_str(settings, "configs.%s.proposal", NULL, config); if (token) @@ -251,9 +251,9 @@ static peer_cfg_t *load_peer_config(private_config_t *this, uintptr_t strength; ike_cfg = load_ike_config(this, settings, config); - peer_cfg = peer_cfg_create(config, 2, ike_cfg, CERT_ALWAYS_SEND, - UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, 0, - NULL, NULL, FALSE, NULL, NULL); + peer_cfg = peer_cfg_create(config, IKEV2, ike_cfg, CERT_ALWAYS_SEND, + UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, 0, 0, + FALSE, NULL, NULL); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); diff --git a/src/conftest/conftest.c b/src/conftest/conftest.c index 48bf9681f..6491fd294 100644 --- a/src/conftest/conftest.c +++ b/src/conftest/conftest.c @@ -289,7 +289,8 @@ static bool load_hooks() pos = strchr(name, '-'); if (pos) { - snprintf(buf, sizeof(buf), "%.*s_hook_create", pos - name, name); + snprintf(buf, sizeof(buf), "%.*s_hook_create", (int)(pos - name), + name); } else { @@ -392,7 +393,7 @@ static void load_loggers(file_logger_t *logger) } logger = file_logger_create(file, NULL, FALSE); load_log_levels(logger, section); - charon->bus->add_listener(charon->bus, &logger->listener); + charon->bus->add_logger(charon->bus, &logger->logger); charon->file_loggers->insert_last(charon->file_loggers, logger); } } @@ -422,7 +423,7 @@ int main(int argc, char *argv[]) library_deinit(); return SS_RC_INITIALIZATION_FAILED; } - if (!libcharon_init()) + if (!libcharon_init("conftest")) { libcharon_deinit(); libhydra_deinit(); @@ -436,7 +437,7 @@ int main(int argc, char *argv[]) logger = file_logger_create(stdout, NULL, FALSE); logger->set_level(logger, DBG_ANY, LEVEL_CTRL); - charon->bus->add_listener(charon->bus, &logger->listener); + charon->bus->add_logger(charon->bus, &logger->logger); charon->file_loggers->insert_last(charon->file_loggers, logger); lib->credmgr->add_set(lib->credmgr, &conftest->creds->set); @@ -488,7 +489,7 @@ int main(int argc, char *argv[]) { return 1; } - if (!charon->initialize(charon)) + if (!charon->initialize(charon, PLUGINS)) { return 1; } diff --git a/src/conftest/hooks/add_notify.c b/src/conftest/hooks/add_notify.c index de46ca81f..9611cad6c 100644 --- a/src/conftest/hooks/add_notify.c +++ b/src/conftest/hooks/add_notify.c @@ -60,9 +60,9 @@ struct private_add_notify_t { METHOD(listener_t, message, bool, private_add_notify_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -85,11 +85,11 @@ METHOD(listener_t, message, bool, data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2); data = chunk_from_hex(data, NULL); } - else if (this->data && strlen(this->data)) + else if (strlen(this->data)) { data = chunk_clone(chunk_create(this->data, strlen(this->data))); } - notify = notify_payload_create_from_protocol_and_type( + notify = notify_payload_create_from_protocol_and_type(NOTIFY, this->esp ? PROTO_ESP : PROTO_IKE, type); notify->set_spi(notify, this->spi); if (data.len) diff --git a/src/conftest/hooks/add_payload.c b/src/conftest/hooks/add_payload.c index 03a47cc23..2903bb20f 100644 --- a/src/conftest/hooks/add_payload.c +++ b/src/conftest/hooks/add_payload.c @@ -62,9 +62,9 @@ struct private_add_payload_t { METHOD(listener_t, message, bool, private_add_payload_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -103,7 +103,7 @@ METHOD(listener_t, message, bool, data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2); data = chunk_from_hex(data, NULL); } - else if (this->data && strlen(this->data)) + else if (strlen(this->data)) { data = chunk_clone(chunk_create(this->data, strlen(this->data))); } diff --git a/src/conftest/hooks/custom_proposal.c b/src/conftest/hooks/custom_proposal.c index e4acd841f..38d4286c4 100644 --- a/src/conftest/hooks/custom_proposal.c +++ b/src/conftest/hooks/custom_proposal.c @@ -19,7 +19,6 @@ #include #include -#include typedef struct private_custom_proposal_t private_custom_proposal_t; @@ -91,7 +90,7 @@ static linked_list_t* load_proposals(private_custom_proposal_t *this, alg = strtoul(value, &end, 10); if (end == value || errno) { - token = proposal_get_token(value, strlen(value)); + token = lib->proposal->get_token(lib->proposal, value); if (!token) { DBG1(DBG_CFG, "unknown algorithm: '%s', skipped", value); @@ -111,9 +110,9 @@ static linked_list_t* load_proposals(private_custom_proposal_t *this, METHOD(listener_t, message, bool, private_custom_proposal_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -145,7 +144,7 @@ METHOD(listener_t, message, bool, proposal->get_protocol(proposal), proposal->get_spi(proposal)); DBG1(DBG_CFG, "injecting custom proposal: %#P", new_props); - new = sa_payload_create_from_proposal_list(new_props); + new = sa_payload_create_from_proposals_v2(new_props); message->add_payload(message, (payload_t*)new); new_props->destroy_offset(new_props, offsetof(proposal_t, destroy)); } diff --git a/src/conftest/hooks/force_cookie.c b/src/conftest/hooks/force_cookie.c index e34f82851..1b044db14 100644 --- a/src/conftest/hooks/force_cookie.c +++ b/src/conftest/hooks/force_cookie.c @@ -32,9 +32,9 @@ struct private_force_cookie_t { METHOD(listener_t, message, bool, private_force_cookie_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming && message->get_request(message) && + if (incoming && plain && message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { enumerator_t *enumerator; @@ -68,7 +68,7 @@ METHOD(listener_t, message, bool, chunk_t data = chunk_from_thing("COOKIE test data"); DBG1(DBG_CFG, "sending COOKIE: %#B", &data); - response = message_create(); + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); dst = message->get_source(message); src = message->get_destination(message); response->set_source(response, src->clone(src)); diff --git a/src/conftest/hooks/ignore_message.c b/src/conftest/hooks/ignore_message.c index 210f3ac50..3cb5f2059 100644 --- a/src/conftest/hooks/ignore_message.c +++ b/src/conftest/hooks/ignore_message.c @@ -45,9 +45,9 @@ struct private_ignore_message_t { METHOD(listener_t, message, bool, private_ignore_message_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming == this->in && + if (incoming == this->in && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c index 2843d60c1..09590d4f3 100644 --- a/src/conftest/hooks/ike_auth_fill.c +++ b/src/conftest/hooks/ike_auth_fill.c @@ -51,7 +51,10 @@ struct private_ike_auth_fill_t { /** size of non ESP-Marker */ #define NON_ESP_MARKER_LEN 4 - +/** length of fixed encryption payload header */ +#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 +/** length of fixed cert payload header */ +#define CERT_PAYLOAD_HEADER_LENGTH 5 /** * Calculate packet size on wire (without ethernet/IP header) */ @@ -89,9 +92,9 @@ static size_t calculate_wire_size(message_t *message, ike_sa_t *ike_sa) METHOD(listener_t, message, bool, private_ike_auth_fill_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -105,7 +108,7 @@ METHOD(listener_t, message, bool, diff = this->bytes - size - CERT_PAYLOAD_HEADER_LENGTH; data = chunk_alloc(diff); memset(data.ptr, 0x12, data.len); - pld = cert_payload_create_custom(201, data); + pld = cert_payload_create_custom(CERTIFICATE, 201, data); message->add_payload(message, &pld->payload_interface); DBG1(DBG_CFG, "inserting %d dummy bytes certificate payload", diff); } diff --git a/src/conftest/hooks/log_id.c b/src/conftest/hooks/log_id.c index ad14cea10..07dd6a44e 100644 --- a/src/conftest/hooks/log_id.c +++ b/src/conftest/hooks/log_id.c @@ -32,9 +32,9 @@ struct private_log_id_t { METHOD(listener_t, message, bool, private_log_id_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/log_ke.c b/src/conftest/hooks/log_ke.c index 231c0a8d8..710482326 100644 --- a/src/conftest/hooks/log_ke.c +++ b/src/conftest/hooks/log_ke.c @@ -32,9 +32,9 @@ struct private_log_ke_t { METHOD(listener_t, message, bool, private_log_ke_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/log_proposals.c b/src/conftest/hooks/log_proposals.c index 8c330ab3d..347b83209 100644 --- a/src/conftest/hooks/log_proposals.c +++ b/src/conftest/hooks/log_proposals.c @@ -32,9 +32,9 @@ struct private_log_proposals_t { METHOD(listener_t, message, bool, private_log_proposals_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator, *proposals; payload_t *payload; diff --git a/src/conftest/hooks/log_ts.c b/src/conftest/hooks/log_ts.c index fb7c89a0a..f212efa12 100644 --- a/src/conftest/hooks/log_ts.c +++ b/src/conftest/hooks/log_ts.c @@ -32,9 +32,9 @@ struct private_log_ts_t { METHOD(listener_t, message, bool, private_log_ts_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index 4b7168cac..4166afc79 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -15,6 +15,7 @@ #include "hook.h" +#include #include #include #include @@ -135,7 +136,7 @@ static void process_auth_request(private_pretend_auth_t *this, static void process_init_response(private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message) { - this->ike_init = message->get_packet_data(message); + this->ike_init = chunk_clone(message->get_packet_data(message)); } /** @@ -153,7 +154,7 @@ static void build_certs(private_pretend_auth_t *this, cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); if (cert) { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); if (payload) { DBG1(DBG_IKE, "pretending end entity cert \"%Y\"", @@ -166,7 +167,7 @@ static void build_certs(private_pretend_auth_t *this, { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); if (payload) { DBG1(DBG_IKE, "pretending issuer cert \"%Y\"", @@ -190,7 +191,7 @@ static bool build_auth(private_pretend_auth_t *this, auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; - keymat_t *keymat; + keymat_v2_t *keymat; auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, this->id, auth); @@ -235,9 +236,13 @@ static bool build_auth(private_pretend_auth_t *this, key_type_names, private->get_type(private)); return FALSE; } - keymat = ike_sa->get_keymat(ike_sa); - octets = keymat->get_auth_octets(keymat, TRUE, this->ike_init, - this->nonce, this->id, this->reserved); + keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + if (!keymat->get_auth_octets(keymat, TRUE, this->ike_init, + this->nonce, this->id, this->reserved, &octets)) + { + private->destroy(private); + return FALSE; + } if (!private->sign(private, scheme, octets, &auth_data)) { chunk_free(&octets); @@ -294,7 +299,7 @@ static void process_auth_response(private_pretend_auth_t *this, if (this->proposal) { message->add_payload(message, (payload_t*) - sa_payload_create_from_proposal(this->proposal)); + sa_payload_create_from_proposal_v2(this->proposal)); } if (this->tsi) { @@ -310,35 +315,38 @@ static void process_auth_response(private_pretend_auth_t *this, METHOD(listener_t, message, bool, private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (plain) { - if (!message->get_request(message)) + if (incoming) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - process_init_response(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) + if (!message->get_request(message)) { - process_auth_response(this, ike_sa, message); + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_init_response(this, ike_sa, message); + } + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { + process_auth_response(this, ike_sa, message); + } } } - } - else - { - if (message->get_request(message)) + else { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - process_init_request(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) + if (message->get_request(message)) { - process_auth_request(this, ike_sa, message); + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_init_request(this, ike_sa, message); + } + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { + process_auth_request(this, ike_sa, message); + } } } } diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c index 993c952e0..b7e6f22e7 100644 --- a/src/conftest/hooks/rebuild_auth.c +++ b/src/conftest/hooks/rebuild_auth.c @@ -15,6 +15,7 @@ #include "hook.h" +#include #include #include #include @@ -57,12 +58,11 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, enumerator_t *enumerator; chunk_t octets, auth_data; private_key_t *private; - auth_cfg_t *auth; payload_t *payload; auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; - keymat_t *keymat; + keymat_v2_t *keymat; identification_t *id; char reserved[3]; generator_t *generator; @@ -90,10 +90,8 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, id = identification_create_from_encoding(data.ptr[4], chunk_skip(data, 8)); generator->destroy(generator); - auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, - this->id ?: id, auth); - auth->destroy(auth); + this->id ?: id, NULL); if (private == NULL) { DBG1(DBG_CFG, "no private key found for '%Y' to rebuild AUTH", @@ -137,9 +135,14 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, id->destroy(id); return FALSE; } - keymat = ike_sa->get_keymat(ike_sa); - octets = keymat->get_auth_octets(keymat, FALSE, this->ike_init, - this->nonce, id, reserved); + keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + if (!keymat->get_auth_octets(keymat, FALSE, this->ike_init, + this->nonce, id, reserved, &octets)) + { + private->destroy(private); + id->destroy(id); + return FALSE; + } if (!private->sign(private, scheme, octets, &auth_data)) { chunk_free(&octets); @@ -174,34 +177,37 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, METHOD(listener_t, message, bool, private_rebuild_auth_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && message->get_message_id(message) == 1) - { - rebuild_auth(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_SA_INIT) + if (plain) { - if (incoming) + if (!incoming && message->get_message_id(message) == 1) { - nonce_payload_t *nonce; - - nonce = (nonce_payload_t*)message->get_payload(message, NONCE); - if (nonce) - { - free(this->nonce.ptr); - this->nonce = nonce->get_nonce(nonce); - } + rebuild_auth(this, ike_sa, message); } - else + if (message->get_exchange_type(message) == IKE_SA_INIT) { - packet_t *packet; - - if (message->generate(message, NULL, &packet) == SUCCESS) + if (incoming) + { + nonce_payload_t *nonce; + + nonce = (nonce_payload_t*)message->get_payload(message, NONCE); + if (nonce) + { + free(this->nonce.ptr); + this->nonce = nonce->get_nonce(nonce); + } + } + else { - free(this->ike_init.ptr); - this->ike_init = chunk_clone(packet->get_data(packet)); - packet->destroy(packet); + packet_t *packet; + + if (message->generate(message, NULL, &packet) == SUCCESS) + { + free(this->ike_init.ptr); + this->ike_init = chunk_clone(packet->get_data(packet)); + packet->destroy(packet); + } } } } diff --git a/src/conftest/hooks/reset_seq.c b/src/conftest/hooks/reset_seq.c index ccf8e997d..6fb7a2e4b 100644 --- a/src/conftest/hooks/reset_seq.c +++ b/src/conftest/hooks/reset_seq.c @@ -51,7 +51,6 @@ static job_requeue_t reset_cb(struct xfrm_usersa_id *data) struct nlmsghdr *hdr; struct xfrm_aevent_id *id; struct rtattr *rthdr; - struct xfrm_replay_state *replay; struct sockaddr_nl addr; int s, len; @@ -74,8 +73,6 @@ static job_requeue_t reset_cb(struct xfrm_usersa_id *data) rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state)); hdr->nlmsg_len += rthdr->rta_len; - replay = (struct xfrm_replay_state*)RTA_DATA(rthdr); - s = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); if (s == -1) { diff --git a/src/conftest/hooks/set_critical.c b/src/conftest/hooks/set_critical.c index caf2215c3..8ec84e13d 100644 --- a/src/conftest/hooks/set_critical.c +++ b/src/conftest/hooks/set_critical.c @@ -47,9 +47,9 @@ struct private_set_critical_t { METHOD(listener_t, message, bool, private_set_critical_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_initiator.c b/src/conftest/hooks/set_ike_initiator.c index 6ba43eaca..1674f0a2d 100644 --- a/src/conftest/hooks/set_ike_initiator.c +++ b/src/conftest/hooks/set_ike_initiator.c @@ -42,9 +42,9 @@ struct private_set_ike_initiator_t { METHOD(listener_t, message, bool, private_set_ike_initiator_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_request.c b/src/conftest/hooks/set_ike_request.c index baabea66a..fd5b6de61 100644 --- a/src/conftest/hooks/set_ike_request.c +++ b/src/conftest/hooks/set_ike_request.c @@ -42,9 +42,9 @@ struct private_set_ike_request_t { METHOD(listener_t, message, bool, private_set_ike_request_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_spi.c b/src/conftest/hooks/set_ike_spi.c index 14a0da9cd..bda02580d 100644 --- a/src/conftest/hooks/set_ike_spi.c +++ b/src/conftest/hooks/set_ike_spi.c @@ -52,9 +52,9 @@ struct private_set_ike_spi_t { METHOD(listener_t, message, bool, private_set_ike_spi_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_version.c b/src/conftest/hooks/set_ike_version.c index d2de9dc81..ca52879d1 100644 --- a/src/conftest/hooks/set_ike_version.c +++ b/src/conftest/hooks/set_ike_version.c @@ -57,9 +57,9 @@ struct private_set_ike_version_t { METHOD(listener_t, message, bool, private_set_ike_version_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_length.c b/src/conftest/hooks/set_length.c index 0379dcb7c..c1a867a99 100644 --- a/src/conftest/hooks/set_length.c +++ b/src/conftest/hooks/set_length.c @@ -50,9 +50,9 @@ struct private_set_length_t { METHOD(listener_t, message, bool, private_set_length_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -76,11 +76,10 @@ METHOD(listener_t, message, bool, if (type == payload->get_type(payload)) { encoding_rule_t *rules; - size_t count; u_int16_t *len; - int i; + int i, count; - payload->get_encoding_rules(payload, &rules, &count); + count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < count; i++) { if (rules[i].type == PAYLOAD_LENGTH) diff --git a/src/conftest/hooks/set_proposal_number.c b/src/conftest/hooks/set_proposal_number.c index a59d96b6d..0cc3cfc63 100644 --- a/src/conftest/hooks/set_proposal_number.c +++ b/src/conftest/hooks/set_proposal_number.c @@ -69,9 +69,9 @@ static void copy_proposal_algs(proposal_t *from, proposal_t *to, METHOD(listener_t, message, bool, private_set_proposal_number_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { @@ -121,7 +121,7 @@ METHOD(listener_t, message, bool, } enumerator->destroy(enumerator); } - sa = sa_payload_create_from_proposal_list(updated); + sa = sa_payload_create_from_proposals_v2(updated); list->destroy_offset(list, offsetof(proposal_t, destroy)); updated->destroy_offset(updated, offsetof(proposal_t, destroy)); message->add_payload(message, (payload_t*)sa); diff --git a/src/conftest/hooks/set_reserved.c b/src/conftest/hooks/set_reserved.c index 77a605d2a..d1a4a977b 100644 --- a/src/conftest/hooks/set_reserved.c +++ b/src/conftest/hooks/set_reserved.c @@ -163,9 +163,9 @@ static void set_byte(private_set_reserved_t *this, message_t *message, METHOD(listener_t, message, bool, private_set_reserved_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/unencrypted_notify.c b/src/conftest/hooks/unencrypted_notify.c index 80bdc64b7..f4c35725c 100644 --- a/src/conftest/hooks/unencrypted_notify.c +++ b/src/conftest/hooks/unencrypted_notify.c @@ -80,11 +80,11 @@ METHOD(listener_t, ike_updown, bool, data = chunk_skip(chunk_create(this->data, strlen(this->data)), 2); data = chunk_from_hex(data, NULL); } - else if (this->data && strlen(this->data)) + else if (strlen(this->data)) { data = chunk_clone(chunk_create(this->data, strlen(this->data))); } - notify = notify_payload_create_from_protocol_and_type( + notify = notify_payload_create_from_protocol_and_type(NOTIFY, this->esp ? PROTO_ESP : PROTO_IKE, type); notify->set_spi(notify, this->spi); if (data.len) @@ -95,7 +95,7 @@ METHOD(listener_t, ike_updown, bool, DBG1(DBG_CFG, "injecting unencrypted INFORMATIONAL message"); - message = message_create(); + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); message->set_message_id(message, this->id); message->set_ike_sa_id(message, ike_sa->get_id(ike_sa)); message->set_exchange_type(message, INFORMATIONAL); diff --git a/src/conftest/hooks/unsort_message.c b/src/conftest/hooks/unsort_message.c index b37b261a4..1b2b302af 100644 --- a/src/conftest/hooks/unsort_message.c +++ b/src/conftest/hooks/unsort_message.c @@ -45,9 +45,9 @@ struct private_unsort_message_t { METHOD(listener_t, message, bool, private_unsort_message_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/dumm/Makefile.in b/src/dumm/Makefile.in index bd172b701..ad24ca998 100644 --- a/src/dumm/Makefile.in +++ b/src/dumm/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -91,7 +92,7 @@ am_irdumm_OBJECTS = irdumm.$(OBJEXT) irdumm_OBJECTS = $(am_irdumm_OBJECTS) irdumm_DEPENDENCIES = libdumm.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -117,6 +118,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -211,11 +213,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -232,11 +237,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -252,6 +258,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -261,7 +268,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/dumm/ext/extconf.rb.in b/src/dumm/ext/extconf.rb.in index 36536ec52..29df65ca7 100644 --- a/src/dumm/ext/extconf.rb.in +++ b/src/dumm/ext/extconf.rb.in @@ -5,7 +5,7 @@ require 'mkmf' $defs << " @DEFS@" -$CFLAGS << " -Wno-format" +$CFLAGS << " -Wno-format -include \"@top_builddir@/config.h\"" dir_config('dumm', '@top_srcdir@/src/dumm', '../.libs') dir_config('strongswan', '@top_srcdir@/src/libstrongswan', '../../libstrongswan/.libs') diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c index de70b7e69..40045cc3a 100644 --- a/src/dumm/mconsole.c +++ b/src/dumm/mconsole.c @@ -150,7 +150,7 @@ static int request(private_mconsole_t *this, void(*cb)(void*,char*,size_t), if (reply.len && *reply.data) { DBG1(DBG_LIB, "received mconsole error %d: %.*s", - reply.err, reply.len, reply.data); + reply.err, (int)reply.len, reply.data); } break; } diff --git a/src/include/Makefile.in b/src/include/Makefile.in index 8bc6befc7..bdf80a49c 100644 --- a/src/include/Makefile.in +++ b/src/include/Makefile.in @@ -48,6 +48,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = @@ -61,6 +62,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -155,11 +157,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -176,11 +181,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -196,6 +202,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -205,7 +212,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/ipsec/Makefile.am b/src/ipsec/Makefile.am index bbf009721..8be28eff8 100644 --- a/src/ipsec/Makefile.am +++ b/src/ipsec/Makefile.am @@ -1,22 +1,35 @@ -sbin_SCRIPTS = ipsec -CLEANFILES = ipsec ipsec.8 -dist_man8_MANS = ipsec.8 -EXTRA_DIST = ipsec.in ipsec.8.in Android.mk +sbin_SCRIPTS = _ipsec +CLEANFILES = _ipsec _ipsec.8 +dist_man8_MANS = _ipsec.8 +EXTRA_DIST = _ipsec.in _ipsec.8.in Android.mk -ipsec.8 : ipsec.8.in +_ipsec.8 : _ipsec.8.in sed \ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ + -e "s:@IPSEC_SCRIPT@:$(ipsec_script):g" \ + -e "s:@IPSEC_SCRIPT_UPPER@:$(ipsec_script_upper):g" \ $(srcdir)/$@.in > $@ -ipsec : ipsec.in +_ipsec : _ipsec.in sed \ -e "s:@IPSEC_SHELL@:/bin/sh:" \ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ -e "s:@IPSEC_NAME@:$(PACKAGE_NAME):" \ -e "s:@IPSEC_DISTRO@::" \ -e "s:@IPSEC_DIR@:$(ipsecdir):" \ + -e "s:@IPSEC_SCRIPT@:$(ipsec_script):" \ -e "s:@IPSEC_SBINDIR@:$(sbindir):" \ -e "s:@IPSEC_CONFDIR@:$(sysconfdir):" \ -e "s:@IPSEC_PIDDIR@:$(piddir):" \ $(srcdir)/$@.in > $@ chmod +x $@ + +install-exec-hook: + mv $(DESTDIR)$(sbindir)/_ipsec $(DESTDIR)$(sbindir)/$(ipsec_script) + +install-data-hook: + mv $(DESTDIR)$(man8dir)/_ipsec.8 $(DESTDIR)$(man8dir)/$(ipsec_script).8 + +uninstall-hook: + rm -f $(DESTDIR)$(sbindir)/$(ipsec_script) + rm -f $(DESTDIR)$(man8dir)/$(ipsec_script).8 diff --git a/src/ipsec/Makefile.in b/src/ipsec/Makefile.in index b0474159d..dbb163f42 100644 --- a/src/ipsec/Makefile.in +++ b/src/ipsec/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,6 +90,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -183,11 +185,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -204,11 +209,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -224,6 +230,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -233,7 +240,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -261,10 +267,10 @@ top_srcdir = @top_srcdir@ urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ -sbin_SCRIPTS = ipsec -CLEANFILES = ipsec ipsec.8 -dist_man8_MANS = ipsec.8 -EXTRA_DIST = ipsec.in ipsec.8.in Android.mk +sbin_SCRIPTS = _ipsec +CLEANFILES = _ipsec _ipsec.8 +dist_man8_MANS = _ipsec.8 +EXTRA_DIST = _ipsec.in _ipsec.8.in Android.mk all: all-am .SUFFIXES: @@ -476,13 +482,15 @@ info: info-am info-am: install-data-am: install-man - + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-sbinSCRIPTS - + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-am install-html-am: @@ -520,43 +528,59 @@ ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-sbinSCRIPTS - + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-hook uninstall-man: uninstall-man8 -.MAKE: install-am install-strip +.MAKE: install-am install-data-am install-exec-am install-strip \ + uninstall-am .PHONY: all all-am check check-am clean clean-generic clean-libtool \ distclean distclean-generic distclean-libtool distdir dvi \ dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-man8 \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-sbinSCRIPTS install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ - ps ps-am uninstall uninstall-am uninstall-man uninstall-man8 \ + install-data install-data-am install-data-hook install-dvi \ + install-dvi-am install-exec install-exec-am install-exec-hook \ + install-html install-html-am install-info install-info-am \ + install-man install-man8 install-pdf install-pdf-am install-ps \ + install-ps-am install-sbinSCRIPTS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-hook uninstall-man uninstall-man8 \ uninstall-sbinSCRIPTS -ipsec.8 : ipsec.8.in +_ipsec.8 : _ipsec.8.in sed \ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ + -e "s:@IPSEC_SCRIPT@:$(ipsec_script):g" \ + -e "s:@IPSEC_SCRIPT_UPPER@:$(ipsec_script_upper):g" \ $(srcdir)/$@.in > $@ -ipsec : ipsec.in +_ipsec : _ipsec.in sed \ -e "s:@IPSEC_SHELL@:/bin/sh:" \ -e "s:@IPSEC_VERSION@:$(PACKAGE_VERSION):" \ -e "s:@IPSEC_NAME@:$(PACKAGE_NAME):" \ -e "s:@IPSEC_DISTRO@::" \ -e "s:@IPSEC_DIR@:$(ipsecdir):" \ + -e "s:@IPSEC_SCRIPT@:$(ipsec_script):" \ -e "s:@IPSEC_SBINDIR@:$(sbindir):" \ -e "s:@IPSEC_CONFDIR@:$(sysconfdir):" \ -e "s:@IPSEC_PIDDIR@:$(piddir):" \ $(srcdir)/$@.in > $@ chmod +x $@ +install-exec-hook: + mv $(DESTDIR)$(sbindir)/_ipsec $(DESTDIR)$(sbindir)/$(ipsec_script) + +install-data-hook: + mv $(DESTDIR)$(man8dir)/_ipsec.8 $(DESTDIR)$(man8dir)/$(ipsec_script).8 + +uninstall-hook: + rm -f $(DESTDIR)$(sbindir)/$(ipsec_script) + rm -f $(DESTDIR)$(man8dir)/$(ipsec_script).8 + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/ipsec/_ipsec.8 b/src/ipsec/_ipsec.8 new file mode 100644 index 000000000..7802fc48f --- /dev/null +++ b/src/ipsec/_ipsec.8 @@ -0,0 +1,291 @@ +.TH IPSEC 8 "2012-06-19" "5.0.1dr3" "strongSwan" +.SH NAME +ipsec \- invoke IPsec utilities +.SH SYNOPSIS +.B ipsec +\fIcommand\fP [ \fIarguments\fP ] [ \fIoptions\fP ] +.PP +.SH DESCRIPTION +The +.B ipsec +utility invokes any of several utilities involved in controlling and monitoring +the IPsec encryption/authentication system, running the specified \fIcommand\fP +with the specified \fIarguments\fP and \fIoptions\fP as if it had been invoked +directly. This largely eliminates possible name collisions with other software, +and also permits some centralized services. +.PP +All the commands described in this manual page are built-in and are used to +control and monitor IPsec connections as well as the IKE daemons. +.PP +For other commands +.I ipsec +supplies the invoked +.I command +with a suitable PATH environment variable, +and also provides IPSEC_DIR, +IPSEC_CONFS, and IPSEC_VERSION environment variables, +containing respectively +the full pathname of the directory where the IPsec utilities are stored, +the full pathname of the directory where the configuration files live, +and the IPsec version number. +.PP +.SS CONTROL COMMANDS +.TP +.B "start [ starter options ]" +calls +.BR "starter" +which in turn parses \fIipsec.conf\fR and starts the IKEv1/IKEv2 daemon +\fIcharon\fR. +.PP +.TP +.B "update" +sends a \fIHUP\fR signal to +.BR "starter" +which in turn determines any changes in \fIipsec.conf\fR +and updates the configuration on the running IKE daemon \fIcharon\fR. +.PP +.TP +.B "reload" +sends a \fIUSR1\fR signal to +.BR "starter" +which in turn reloads the whole configuration on the running IKE daemon +\fIcharon\fR based on the actual \fIipsec.conf\fR. +.PP +.TP +.B "restart" +is equivalent to +.B "stop" +followed by +.B "start" +after a guard of 2 seconds. +.PP +.TP +.B "stop" +terminates all IPsec connections and stops the IKE daemon \fIcharon\fR +by sending a \fITERM\fR signal to +.BR "starter". +.PP +.TP +.B "up \fIname\fP" +tells the IKE daemon to start up connection \fIname\fP. +.PP +.TP +.B "down \fIname\fP" +tells the IKE daemon to terminate connection \fIname\fP. +.PP +.TP +.B "down \fIname{n}\fP" +terminates IKEv1 Quick Mode and IKEv2 CHILD SA instance \fIn\fP of +connection \fIname\fP. +.PP +.TP +.B "down \fIname{*}\fP" +terminates all IKEv1 Quick Mode and IKEv2 CHILD SA instances of connection +\fIname\fP. +.PP +.TP +.B "down \fIname[n]\fP" +terminates IKE SA instance \fIn\fP of connection \fIname\fP. +.PP +.TP +.B "down \fIname[*]\fP" +terminates all IKE SA instances of connection \fIname\fP. +.PP +.TP +.B "route \fIname\fP" +tells the IKE daemon to insert an IPsec policy in the kernel +for connection \fIname\fP. The first payload packet matching the IPsec policy +will automatically trigger an IKE connection setup. +.PP +.TP +.B "unroute \fIname\fP" +remove the IPsec policy in the kernel for connection \fIname\fP. +.PP +.TP +.B "status [ \fIname\fP ]" +returns concise status information either on connection +\fIname\fP or if the argument is lacking, on all connections. +.PP +.TP +.B "statusall [ \fIname\fP ]" +returns detailed status information either on connection +\fIname\fP or if the argument is lacking, on all connections. +.PP +.SS LIST COMMANDS +.TP +.B "listalgs" +returns a list supported cryptographic algorithms usable for IKE, and their +corresponding plugin. +.PP +.TP +.B "listpubkeys [ --utc ]" +returns a list of RSA public keys that were either loaded in raw key format +or extracted from X.509 and|or OpenPGP certificates. +.PP +.TP +.B "listcerts [ --utc ]" +returns a list of X.509 and|or OpenPGP certificates that were either loaded +locally by the IKE daemon or received via the IKE protocol. +.PP +.TP +.B "listcacerts [ --utc ]" +returns a list of X.509 Certification Authority (CA) certificates that were +loaded locally by the IKE daemon from the \fI/etc/ipsec.d/cacerts/\fP +directory or received via the IKE protocol. +.PP +.TP +.B "listaacerts [ --utc ]" +returns a list of X.509 Authorization Authority (AA) certificates that were +loaded locally by the IKE daemon from the \fI/etc/ipsec.d/aacerts/\fP +directory. +.PP +.TP +.B "listocspcerts [ --utc ]" +returns a list of X.509 OCSP Signer certificates that were either loaded +locally by the IKE daemon from the \fI/etc/ipsec.d/ocspcerts/\fP +directory or were sent by an OCSP server. +.PP +.TP +.B "listacerts [ --utc ]" +returns a list of X.509 Attribute certificates that were loaded locally by +the IKE daemon from the \fI/etc/ipsec.d/acerts/\fP directory. +.PP +.TP +.B "listgroups [ --utc ]" +returns a list of groups that are used to define user authorization profiles. +.PP +.TP +.B "listcainfos [ --utc ]" +returns certification authority information (CRL distribution points, OCSP URIs, +LDAP servers) that were defined by +.BR ca +sections in \fIipsec.conf\fP. +.PP +.TP +.B "listcrls [ --utc ]" +returns a list of Certificate Revocation Lists (CRLs) that were either loaded +by the IKE daemon from the \fI/etc/ipsec.d/crls\fP directory or fetched from +an HTTP- or LDAP-based CRL distribution point. +.PP +.TP +.B "listocsp [ --utc ]" +returns revocation information fetched from OCSP servers. +.PP +.TP +.B "listall [ --utc ]" +returns all information generated by the list commands above. Each list command +can be called with the +\fB\-\-utc\fP +option which displays all dates in UTC instead of local time. +.PP +.SS REREAD COMMANDS +.TP +.B "rereadsecrets" +flushes and rereads all secrets defined in \fIipsec.secrets\fP. +.PP +.TP +.B "rereadcacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP +directory and adds them to the list of Certification Authority (CA) +certificates. +.PP +.TP +.B "rereadaacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP +directory and adds them to the list of Authorization Authority (AA) +certificates. +.PP +.TP +.B "rereadocspcerts" +reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP +directory and adds them to the list of OCSP signer certificates. +.PP +.TP +.B "rereadacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP +directory and adds them to the list of attribute certificates. +.PP +.TP +.B "rereadcrls" +reads all Certificate Revocation Lists (CRLs) contained in the +\fI/etc/ipsec.d/crls/\fP directory and adds them to the list of CRLs. +.PP +.TP +.B "rereadall" +executes all reread commands listed above. +.PP +.SS PURGE COMMANDS +.TP +.B "purgeike" +purges IKE SAs that don't have a Quick Mode or CHILD SA. +.PP +.TP +.B "purgeocsp" +purges all cached OCSP information records. +.PP +.SS INFO COMMANDS +.TP +.B "\-\-help" +returns the usage information for the +.B ipsec +command. +.PP +.TP +.B "\-\-version" +returns the version in the form of +.B Linux strongSwan U/K +if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is +running on. +.PP +.TP +.B "\-\-versioncode" +returns the version number in the form of +.B U/K +if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is +running on. +.PP +.TP +.B "\-\-copyright" +returns the copyright information. +.PP +.TP +.B "\-\-directory" +returns the \fILIBEXECDIR\fP directory as defined by the configure options. +.PP +.TP +.B "\-\-confdir" +returns the \fISYSCONFDIR\fP directory as defined by the configure options. +.SH FILES +/usr/local/lib/ipsec usual utilities directory +.SH ENVIRONMENT +.PP +The following environment variables control where strongSwan finds its +components. +The +.B ipsec +command sets them if they are not already set. +.nf +.na + +IPSEC_DIR directory containing ipsec programs and utilities +IPSEC_SBINDIR directory containing \fBipsec\fP command +IPSEC_CONFDIR directory containing configuration files +IPSEC_PIDDIR directory containing PID files +IPSEC_SCRIPT name of the ipsec script +IPSEC_NAME name of ipsec distribution +IPSEC_VERSION version numer of ipsec userland and kernel +IPSEC_STARTER_PID PID file for ipsec starter +IPSEC_CHARON_PID PID file for IKE keying daemon +.ad +.fi +.SH SEE ALSO +.hy 0 +.na +ipsec.conf(5), ipsec.secrets(5) +.ad +.hy +.PP +.SH HISTORY +Originally written for the FreeS/WAN project by Henry Spencer. +Updated and extended for the strongSwan project by +Tobias Brunner and Andreas Steffen. diff --git a/src/ipsec/_ipsec.8.in b/src/ipsec/_ipsec.8.in new file mode 100644 index 000000000..41c6ff8d2 --- /dev/null +++ b/src/ipsec/_ipsec.8.in @@ -0,0 +1,291 @@ +.TH @IPSEC_SCRIPT_UPPER@ 8 "2012-06-19" "@IPSEC_VERSION@" "strongSwan" +.SH NAME +@IPSEC_SCRIPT@ \- invoke IPsec utilities +.SH SYNOPSIS +.B @IPSEC_SCRIPT@ +\fIcommand\fP [ \fIarguments\fP ] [ \fIoptions\fP ] +.PP +.SH DESCRIPTION +The +.B @IPSEC_SCRIPT@ +utility invokes any of several utilities involved in controlling and monitoring +the IPsec encryption/authentication system, running the specified \fIcommand\fP +with the specified \fIarguments\fP and \fIoptions\fP as if it had been invoked +directly. This largely eliminates possible name collisions with other software, +and also permits some centralized services. +.PP +All the commands described in this manual page are built-in and are used to +control and monitor IPsec connections as well as the IKE daemons. +.PP +For other commands +.I @IPSEC_SCRIPT@ +supplies the invoked +.I command +with a suitable PATH environment variable, +and also provides IPSEC_DIR, +IPSEC_CONFS, and IPSEC_VERSION environment variables, +containing respectively +the full pathname of the directory where the IPsec utilities are stored, +the full pathname of the directory where the configuration files live, +and the IPsec version number. +.PP +.SS CONTROL COMMANDS +.TP +.B "start [ starter options ]" +calls +.BR "starter" +which in turn parses \fIipsec.conf\fR and starts the IKEv1/IKEv2 daemon +\fIcharon\fR. +.PP +.TP +.B "update" +sends a \fIHUP\fR signal to +.BR "starter" +which in turn determines any changes in \fIipsec.conf\fR +and updates the configuration on the running IKE daemon \fIcharon\fR. +.PP +.TP +.B "reload" +sends a \fIUSR1\fR signal to +.BR "starter" +which in turn reloads the whole configuration on the running IKE daemon +\fIcharon\fR based on the actual \fIipsec.conf\fR. +.PP +.TP +.B "restart" +is equivalent to +.B "stop" +followed by +.B "start" +after a guard of 2 seconds. +.PP +.TP +.B "stop" +terminates all IPsec connections and stops the IKE daemon \fIcharon\fR +by sending a \fITERM\fR signal to +.BR "starter". +.PP +.TP +.B "up \fIname\fP" +tells the IKE daemon to start up connection \fIname\fP. +.PP +.TP +.B "down \fIname\fP" +tells the IKE daemon to terminate connection \fIname\fP. +.PP +.TP +.B "down \fIname{n}\fP" +terminates IKEv1 Quick Mode and IKEv2 CHILD SA instance \fIn\fP of +connection \fIname\fP. +.PP +.TP +.B "down \fIname{*}\fP" +terminates all IKEv1 Quick Mode and IKEv2 CHILD SA instances of connection +\fIname\fP. +.PP +.TP +.B "down \fIname[n]\fP" +terminates IKE SA instance \fIn\fP of connection \fIname\fP. +.PP +.TP +.B "down \fIname[*]\fP" +terminates all IKE SA instances of connection \fIname\fP. +.PP +.TP +.B "route \fIname\fP" +tells the IKE daemon to insert an IPsec policy in the kernel +for connection \fIname\fP. The first payload packet matching the IPsec policy +will automatically trigger an IKE connection setup. +.PP +.TP +.B "unroute \fIname\fP" +remove the IPsec policy in the kernel for connection \fIname\fP. +.PP +.TP +.B "status [ \fIname\fP ]" +returns concise status information either on connection +\fIname\fP or if the argument is lacking, on all connections. +.PP +.TP +.B "statusall [ \fIname\fP ]" +returns detailed status information either on connection +\fIname\fP or if the argument is lacking, on all connections. +.PP +.SS LIST COMMANDS +.TP +.B "listalgs" +returns a list supported cryptographic algorithms usable for IKE, and their +corresponding plugin. +.PP +.TP +.B "listpubkeys [ --utc ]" +returns a list of RSA public keys that were either loaded in raw key format +or extracted from X.509 and|or OpenPGP certificates. +.PP +.TP +.B "listcerts [ --utc ]" +returns a list of X.509 and|or OpenPGP certificates that were either loaded +locally by the IKE daemon or received via the IKE protocol. +.PP +.TP +.B "listcacerts [ --utc ]" +returns a list of X.509 Certification Authority (CA) certificates that were +loaded locally by the IKE daemon from the \fI/etc/ipsec.d/cacerts/\fP +directory or received via the IKE protocol. +.PP +.TP +.B "listaacerts [ --utc ]" +returns a list of X.509 Authorization Authority (AA) certificates that were +loaded locally by the IKE daemon from the \fI/etc/ipsec.d/aacerts/\fP +directory. +.PP +.TP +.B "listocspcerts [ --utc ]" +returns a list of X.509 OCSP Signer certificates that were either loaded +locally by the IKE daemon from the \fI/etc/ipsec.d/ocspcerts/\fP +directory or were sent by an OCSP server. +.PP +.TP +.B "listacerts [ --utc ]" +returns a list of X.509 Attribute certificates that were loaded locally by +the IKE daemon from the \fI/etc/ipsec.d/acerts/\fP directory. +.PP +.TP +.B "listgroups [ --utc ]" +returns a list of groups that are used to define user authorization profiles. +.PP +.TP +.B "listcainfos [ --utc ]" +returns certification authority information (CRL distribution points, OCSP URIs, +LDAP servers) that were defined by +.BR ca +sections in \fIipsec.conf\fP. +.PP +.TP +.B "listcrls [ --utc ]" +returns a list of Certificate Revocation Lists (CRLs) that were either loaded +by the IKE daemon from the \fI/etc/ipsec.d/crls\fP directory or fetched from +an HTTP- or LDAP-based CRL distribution point. +.PP +.TP +.B "listocsp [ --utc ]" +returns revocation information fetched from OCSP servers. +.PP +.TP +.B "listall [ --utc ]" +returns all information generated by the list commands above. Each list command +can be called with the +\fB\-\-utc\fP +option which displays all dates in UTC instead of local time. +.PP +.SS REREAD COMMANDS +.TP +.B "rereadsecrets" +flushes and rereads all secrets defined in \fIipsec.secrets\fP. +.PP +.TP +.B "rereadcacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP +directory and adds them to the list of Certification Authority (CA) +certificates. +.PP +.TP +.B "rereadaacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP +directory and adds them to the list of Authorization Authority (AA) +certificates. +.PP +.TP +.B "rereadocspcerts" +reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP +directory and adds them to the list of OCSP signer certificates. +.PP +.TP +.B "rereadacerts" +reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP +directory and adds them to the list of attribute certificates. +.PP +.TP +.B "rereadcrls" +reads all Certificate Revocation Lists (CRLs) contained in the +\fI/etc/ipsec.d/crls/\fP directory and adds them to the list of CRLs. +.PP +.TP +.B "rereadall" +executes all reread commands listed above. +.PP +.SS PURGE COMMANDS +.TP +.B "purgeike" +purges IKE SAs that don't have a Quick Mode or CHILD SA. +.PP +.TP +.B "purgeocsp" +purges all cached OCSP information records. +.PP +.SS INFO COMMANDS +.TP +.B "\-\-help" +returns the usage information for the +.B @IPSEC_SCRIPT@ +command. +.PP +.TP +.B "\-\-version" +returns the version in the form of +.B Linux strongSwan U/K +if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is +running on. +.PP +.TP +.B "\-\-versioncode" +returns the version number in the form of +.B U/K +if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is +running on. +.PP +.TP +.B "\-\-copyright" +returns the copyright information. +.PP +.TP +.B "\-\-directory" +returns the \fILIBEXECDIR\fP directory as defined by the configure options. +.PP +.TP +.B "\-\-confdir" +returns the \fISYSCONFDIR\fP directory as defined by the configure options. +.SH FILES +/usr/local/lib/ipsec usual utilities directory +.SH ENVIRONMENT +.PP +The following environment variables control where strongSwan finds its +components. +The +.B @IPSEC_SCRIPT@ +command sets them if they are not already set. +.nf +.na + +IPSEC_DIR directory containing ipsec programs and utilities +IPSEC_SBINDIR directory containing \fBipsec\fP command +IPSEC_CONFDIR directory containing configuration files +IPSEC_PIDDIR directory containing PID files +IPSEC_SCRIPT name of the ipsec script +IPSEC_NAME name of ipsec distribution +IPSEC_VERSION version numer of ipsec userland and kernel +IPSEC_STARTER_PID PID file for ipsec starter +IPSEC_CHARON_PID PID file for IKE keying daemon +.ad +.fi +.SH SEE ALSO +.hy 0 +.na +ipsec.conf(5), ipsec.secrets(5) +.ad +.hy +.PP +.SH HISTORY +Originally written for the FreeS/WAN project by Henry Spencer. +Updated and extended for the strongSwan project by +Tobias Brunner and Andreas Steffen. diff --git a/src/ipsec/_ipsec.in b/src/ipsec/_ipsec.in new file mode 100644 index 000000000..2acf5a3f6 --- /dev/null +++ b/src/ipsec/_ipsec.in @@ -0,0 +1,335 @@ +#! @IPSEC_SHELL@ +# prefix command to run stuff from our programs directory +# Copyright (C) 1998-2002 Henry Spencer. +# Copyright (C) 2006 Andreas Steffen +# Copyright (C) 2006 Martin Willi +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. See . +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# define a minimum PATH environment in case it is not set +PATH="/sbin:/bin:/usr/sbin:/usr/bin:@IPSEC_SBINDIR@" +export PATH + +# name and version of the ipsec implementation +OS_NAME=`uname -s` +IPSEC_NAME="@IPSEC_NAME@" +IPSEC_VERSION="U@IPSEC_VERSION@/K`uname -r`" + +# where the private directory and the config files are +IPSEC_DIR="@IPSEC_DIR@" +IPSEC_SBINDIR="@IPSEC_SBINDIR@" +IPSEC_CONFDIR="@IPSEC_CONFDIR@" +IPSEC_PIDDIR="@IPSEC_PIDDIR@" +IPSEC_SCRIPT="@IPSEC_SCRIPT@" + +IPSEC_STARTER_PID="${IPSEC_PIDDIR}/starter.pid" +IPSEC_CHARON_PID="${IPSEC_PIDDIR}/charon.pid" + +IPSEC_STROKE="${IPSEC_DIR}/stroke" +IPSEC_STARTER="${IPSEC_DIR}/starter" + +export IPSEC_DIR IPSEC_SBINDIR IPSEC_CONFDIR IPSEC_PIDDIR IPSEC_SCRIPT IPSEC_VERSION IPSEC_NAME IPSEC_STARTER_PID IPSEC_CHARON_PID + +IPSEC_DISTRO="Institute for Internet Technologies and Applications\nUniversity of Applied Sciences Rapperswil, Switzerland" + +case "$1" in +'') + echo "Usage: $IPSEC_SCRIPT command argument ..." + echo "Use --help for list of commands, or see $IPSEC_SCRIPT(8) manual " + echo "page or the $IPSEC_NAME documentation for names of the common " + echo "ones." + echo "See for more general info." + exit 0 + ;; +--help) + echo "Usage: $IPSEC_SCRIPT command argument ..." + echo "where command is one of:" + echo " start|restart arguments..." + echo " update|reload|stop" + echo " up|down|route|unroute " + echo " status|statusall []" + echo " listalgs|listpubkeys|listcerts [--utc]" + echo " listcacerts|listaacerts|listocspcerts [--utc]" + echo " listacerts|listgroups|listcainfos [--utc]" + echo " listcrls|listocsp|listcards|listplugins|listall [--utc]" + echo " leases [ [
]]" + echo " rereadsecrets|rereadgroups" + echo " rereadcacerts|rereadaacerts|rereadocspcerts" + echo " rereadacerts|rereadcrls|rereadall" + echo " purgeocsp|purgecrls|purgecerts|purgeike" + echo " openac" + echo " scepclient" + echo " secrets" + echo " starter" + echo " version" + echo " stroke" + echo + echo "Some of these functions have their own manual pages, e.g. ipsec_scepclient(8)." + exit 0 + ;; +--versioncode) + echo "$IPSEC_VERSION" + exit 0 + ;; +--directory) + echo "$IPSEC_DIR" + exit 0 + ;; +--confdir) + echo "$IPSEC_CONFDIR" + exit 0 + ;; +copyright|--copyright) + set _copyright + # and fall through, invoking "ipsec _copyright" + ;; +down) + shift + if [ "$#" -ne 1 ] + then + echo "Usage: $IPSEC_SCRIPT down " + exit 2 + fi + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE down "$1" + rc="$?" + fi + exit "$rc" + ;; +down-srcip) + shift + if [ "$#" -lt 1 ] + then + echo "Usage: $IPSEC_SCRIPT down-srcip []" + exit 2 + fi + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE down-srcip $* + rc="$?" + fi + exit "$rc" + ;; +listcards|rereadgroups) + op="$1" + shift + if [ -e $IPSEC_CHARON_PID ] + then + exit 3 + else + exit 7 + fi + ;; +leases) + op="$1" + rc=7 + shift + if [ -e $IPSEC_CHARON_PID ] + then + case "$#" in + 0) $IPSEC_STROKE "$op" ;; + 1) $IPSEC_STROKE "$op" "$1" ;; + *) $IPSEC_STROKE "$op" "$1" "$2" ;; + esac + rc="$?" + fi + exit "$rc" + ;; +listalgs|listpubkeys|listplugins|\ +listcerts|listcacerts|listaacerts|\ +listacerts|listgroups|listocspcerts|\ +listcainfos|listcrls|listocsp|listall|\ +rereadsecrets|rereadcacerts|rereadaacerts|\ +rereadacerts|rereadocspcerts|rereadcrls|\ +rereadall|purgeocsp) + op="$1" + rc=7 + shift + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE "$op" "$@" + rc="$?" + fi + exit "$rc" + ;; +purgeike|purgecrls|purgecerts) + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE "$1" + rc="$?" + fi + exit "$rc" + ;; +reload) + rc=7 + if [ -e $IPSEC_STARTER_PID ] + then + echo "Reloading strongSwan IPsec configuration..." >&2 + kill -USR1 `cat $IPSEC_STARTER_PID` 2>/dev/null && rc=0 + else + echo "Reloading strongSwan IPsec failed: starter is not running" >&2 + fi + exit "$rc" + ;; +restart) + $IPSEC_SBINDIR/$IPSEC_SCRIPT stop + sleep 2 + shift + exec $IPSEC_SBINDIR/$IPSEC_SCRIPT start "$@" + ;; +route|unroute) + op="$1" + rc=7 + shift + if [ "$#" -ne 1 ] + then + echo "Usage: $IPSEC_SCRIPT $op " + exit 2 + fi + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE "$op" "$1" + rc="$?" + fi + exit "$rc" + ;; +secrets) + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE rereadsecrets + rc="$?" + fi + exit "$rc" + ;; +start) + shift + if [ -d /var/lock/subsys ]; then + touch /var/lock/subsys/ipsec + fi + exec $IPSEC_STARTER "$@" + ;; +status|statusall) + op="$1" + # Return value is slightly different for the status command: + # 0 - service up and running + # 1 - service dead, but /var/run/ pid file exists + # 2 - service dead, but /var/lock/ lock file exists + # 3 - service not running (unused) + # 4 - service status unknown :-( + # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) + shift + if [ $# -eq 0 ] + then + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE "$op" + fi + else + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE "$op" "$1" + fi + fi + if [ -e $IPSEC_STARTER_PID ] + then + kill -0 `cat $IPSEC_STARTER_PID` 2>/dev/null + exit $? + fi + exit 3 + ;; +stop) + # stopping a not-running service is considered as success + if [ -e $IPSEC_STARTER_PID ] + then + echo "Stopping strongSwan IPsec..." >&2 + spid=`cat $IPSEC_STARTER_PID` + if [ -n "$spid" ] + then + kill $spid 2>/dev/null + loop=11 + while [ $loop -gt 0 ] ; do + kill -0 $spid 2>/dev/null || break + sleep 1 + loop=$(($loop - 1)) + done + if [ $loop -eq 0 ] + then + kill -KILL $spid 2>/dev/null + rm -f $IPSEC_STARTER_PID + fi + fi + else + echo "Stopping strongSwan IPsec failed: starter is not running" >&2 + fi + if [ -d /var/lock/subsys ]; then + rm -f /var/lock/subsys/ipsec + fi + exit 0 + ;; +up) + shift + if [ "$#" -ne 1 ] + then + echo "Usage: $IPSEC_SCRIPT up " + exit 2 + fi + rc=7 + if [ -e $IPSEC_CHARON_PID ] + then + $IPSEC_STROKE up "$1" + rc="$?" + fi + exit "$rc" + ;; +update) + if [ -e $IPSEC_STARTER_PID ] + then + echo "Updating strongSwan IPsec configuration..." >&2 + kill -HUP `cat $IPSEC_STARTER_PID` + exit 0 + else + echo "Updating strongSwan IPsec failed: starter is not running" >&2 + exit 7 + fi + ;; +version|--version) + printf "$OS_NAME $IPSEC_NAME $IPSEC_VERSION\n" + printf "$IPSEC_DISTRO\n" + printf "See '$IPSEC_SCRIPT --copyright' for copyright information.\n" + exit 0 + ;; +--*) + echo "$0: unknown option \`$1' (perhaps command name was omitted?)" >&2 + exit 2 + ;; +esac + +cmd="$1" +shift + +path="$IPSEC_DIR/$cmd" + +if [ ! -x "$path" ] +then + path="$IPSEC_DIR/$cmd" + if [ ! -x "$path" ] + then + echo "$0: unknown IPsec command \`$cmd' (\`$IPSEC_SCRIPT --help' for list)" >&2 + exit 2 + fi +fi + +exec $path "$@" diff --git a/src/ipsec/ipsec.8 b/src/ipsec/ipsec.8 deleted file mode 100644 index 66e43b481..000000000 --- a/src/ipsec/ipsec.8 +++ /dev/null @@ -1,302 +0,0 @@ -.TH IPSEC 8 "2010-05-30" "4.5.3dr3" "strongSwan" -.SH NAME -ipsec \- invoke IPsec utilities -.SH SYNOPSIS -.B ipsec -\fIcommand\fP [ \fIarguments\fP ] [ \fIoptions\fP ] -.PP -.SH DESCRIPTION -The -.B ipsec -utility invokes any of several utilities involved in controlling and monitoring -the IPsec encryption/authentication system, running the specified \fIcommand\fP -with the specified \fIarguments\fP and \fIoptions\fP as if it had been invoked -directly. This largely eliminates possible name collisions with other software, -and also permits some centralized services. -.PP -All the commands described in this manual page are built-in and are used to -control and monitor IPsec connections as well as the IKE daemons. -.PP -For other commands -.I ipsec -supplies the invoked -.I command -with a suitable PATH environment variable, -and also provides IPSEC_DIR, -IPSEC_CONFS, and IPSEC_VERSION environment variables, -containing respectively -the full pathname of the directory where the IPsec utilities are stored, -the full pathname of the directory where the configuration files live, -and the IPsec version number. -.PP -.SS CONTROL COMMANDS -.TP -.B "ipsec start [ starter options ]" -calls -.BR "ipsec starter" -which in turn parses \fIipsec.conf\fR and starts the IKEv1 \fIpluto\fR and -IKEv2 \fIcharon\fR daemons. -.PP -.TP -.B "ipsec update" -sends a \fIHUP\fR signal to -.BR "ipsec starter" -which in turn determines any changes in \fIipsec.conf\fR -and updates the configuration on the running IKEv1 \fIpluto\fR and IKEv2 -\fIcharon\fR daemons, correspondingly. -.PP -.TP -.B "ipsec reload" -sends a \fIUSR1\fR signal to -.BR "ipsec starter" -which in turn reloads the whole configuration on the running IKEv1 \fIpluto\fR -and IKEv2 \fIcharon\fR daemons based on the actual \fIipsec.conf\fR. -.PP -.TP -.B "ipsec restart" -is equivalent to -.B "ipsec stop" -followed by -.B "ipsec start" -after a guard of 2 seconds. -.PP -.TP -.B "ipsec stop" -terminates all IPsec connections and stops the IKEv1 \fIpluto\fR and IKEv2 -\fIcharon\fR daemons by sending a \fITERM\fR signal to -.BR "ipsec starter". -.PP -.TP -.B "ipsec up \fIname\fP" -tells the responsible IKE daemon to start up connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname\fP" -tells the responsible IKE daemon to terminate connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname{n}\fP" -terminates IKEv2 CHILD SA instance \fIn\fP of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname{*}\fP" -terminates all IKEv2 CHILD SA instances of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname[n]\fP" -terminates all IKEv2 IKE SA instance \fIn\fP of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname[*]\fP" -terminates all IKEv2 IKE SA instances of connection \fIname\fP. -.PP -.TP -.B "ipsec route \fIname\fP" -tells the responsible IKE daemon to insert an IPsec policy in the kernel -for connection \fIname\fP. The first payload packet matching the IPsec policy -will automatically trigger an IKE connection setup. -.PP -.TP -.B "ipsec unroute \fIname\fP" -remove the IPsec policy in the kernel for connection \fIname\fP. -.PP -.TP -.B "ipsec status [ \fIname\fP ]" -returns concise status information either on connection -\fIname\fP or if the argument is lacking, on all connections. -.PP -.TP -.B "ipsec statusall [ \fIname\fP ]" -returns detailed status information either on connection -\fIname\fP or if the argument is lacking, on all connections. -.PP -.SS LIST COMMANDS -.TP -.B "ipsec listalgs" -returns a list all supported IKE encryption and hash algorithms, the available -Diffie-Hellman groups, as well as all supported ESP encryption and -authentication algorithms registered via the Linux kernel's Crypto API. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listpubkeys [ --utc ]" -returns a list of RSA public keys that were either loaded in raw key format -or extracted from X.509 and|or OpenPGP certificates. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listcerts [ --utc ]" -returns a list of X.509 and|or OpenPGP certificates that were either loaded -locally by the IKE daemon or received via the IKEv2 protocol. -.PP -.TP -.B "ipsec listcacerts [ --utc ]" -returns a list of X.509 Certification Authority (CA) certificates that were -loaded locally by the IKE daemon from the \fI/etc/ipsec.d/cacerts/\fP -directory or received in PKCS#7-wrapped certificate payloads via the IKE -protocol. -.PP -.TP -.B "ipsec listaacerts [ --utc ]" -returns a list of X.509 Authorization Authority (AA) certificates that were -loaded locally by the IKE daemon from the \fI/etc/ipsec.d/aacerts/\fP -directory. -.PP -.TP -.B "ipsec listocspcerts [ --utc ]" -returns a list of X.509 OCSP Signer certificates that were either loaded -locally by the IKE daemon from the \fI/etc/ipsec.d/ocspcerts/\fP -directory or were sent by an OCSP server. -.PP -.TP -.B "ipsec listacerts [ --utc ]" -returns a list of X.509 Attribute certificates that were loaded locally by -the IKE daemon from the \fI/etc/ipsec.d/acerts/\fP directory. -.PP -.TP -.B "ipsec listgroups [ --utc ]" -returns a list of groups that are used to define user authorization profiles. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listcainfos [ --utc ]" -returns certification authority information (CRL distribution points, OCSP URIs, -LDAP servers) that were defined by -.BR ca -sections in \fIipsec.conf\fP. -.PP -.TP -.B "ipsec listcrls [ --utc ]" -returns a list of Certificate Revocation Lists (CRLs) that were either loaded -by the IKE daemon from the \fI/etc/ipsec.d/crls\fP directory or fetched from -an HTTP- or LDAP-based CRL distribution point. -.PP -.TP -.B "ipsec listocsp [ --utc ]" -returns revocation information fetched from OCSP servers. -.PP -.TP -.B "ipsec listcards [ --utc ]" -list all certificates found on attached smart cards. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listall [ --utc ]" -returns all information generated by the list commands above. Each list command -can be called with the -\fB\-\-utc\fP -option which displays all dates in UTC instead of local time. -.PP -.SS REREAD COMMANDS -.TP -.B "ipsec rereadsecrets" -flushes and rereads all secrets defined in \fIipsec.secrets\fP. -.PP -.TP -.B "ipsec rereadcacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP -directory and adds them to the list of Certification Authority (CA) -certificates. -.PP -.TP -.B "ipsec rereadaacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP -directory and adds them to the list of Authorization Authority (AA) -certificates. -.PP -.TP -.B "ipsec rereadocspcerts" -reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP -directory and adds them to the list of OCSP signer certificates. -.PP -.TP -.B "ipsec rereadacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP -directory and adds them to the list of attribute certificates. -.PP -.TP -.B "ipsec rereadcrls" -reads all Certificate Revocation Lists (CRLs) contained in the -\fI/etc/ipsec.d/crls/\fP directory and adds them to the list of CRLs. -.PP -.TP -.B "ipsec rereadall" -executes all reread commands listed above. -.PP -.SS PURGE COMMANDS -.TP -.B "ipsec purgeike" -purges IKEv2 SAs that don't have a CHILD SA. -.PP -.TP -.B "ipsec purgeocsp" -purges all cached OCSP information records. -.PP -.SS INFO COMMANDS -.TP -.B "ipsec \-\-help" -returns the usage information for the ipsec command. -.PP -.TP -.B "ipsec \-\-version" -returns the version in the form of -.B Linux strongSwan U/K -if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is -running on. -.PP -.TP -.B "ipsec \-\-versioncode" -returns the version number in the form of -.B U/K -if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is -running on. -.PP -.TP -.B "ipsec \-\-copyright" -returns the copyright information. -.PP -.TP -.B "ipsec \-\-directory" -returns the \fILIBEXECDIR\fP directory as defined by the configure options. -.PP -.TP -.B "ipsec \-\-confdir" -returns the \fISYSCONFDIR\fP directory as defined by the configure options. -.SH FILES -/usr/local/lib/ipsec usual utilities directory -.SH ENVIRONMENT -.PP -The following environment variables control where strongSwan finds its -components. -The -.B ipsec -command sets them if they are not already set. -.nf -.na - -IPSEC_DIR directory containing ipsec programs and utilities -IPSEC_SBINDIR directory containing \fBipsec\fP command -IPSEC_CONFDIR directory containing configuration files -IPSEC_PIDDIR directory containing PID files -IPSEC_NAME name of ipsec distribution -IPSEC_VERSION version numer of ipsec userland and kernel -IPSEC_STARTER_PID PID file for ipsec starter -IPSEC_PLUTO_PID PID file for IKEv1 keying daemon -IPSEC_CHARON_PID PID file for IKEv2 keying daemon -.ad -.fi -.SH SEE ALSO -.hy 0 -.na -ipsec.conf(5), ipsec.secrets(5) -.ad -.hy -.PP -.SH HISTORY -Originally written for the FreeS/WAN project by Henry Spencer. -Updated and extended for the strongSwan project by -Tobias Brunner and Andreas Steffen. diff --git a/src/ipsec/ipsec.8.in b/src/ipsec/ipsec.8.in deleted file mode 100644 index 24a796392..000000000 --- a/src/ipsec/ipsec.8.in +++ /dev/null @@ -1,302 +0,0 @@ -.TH IPSEC 8 "2010-05-30" "@IPSEC_VERSION@" "strongSwan" -.SH NAME -ipsec \- invoke IPsec utilities -.SH SYNOPSIS -.B ipsec -\fIcommand\fP [ \fIarguments\fP ] [ \fIoptions\fP ] -.PP -.SH DESCRIPTION -The -.B ipsec -utility invokes any of several utilities involved in controlling and monitoring -the IPsec encryption/authentication system, running the specified \fIcommand\fP -with the specified \fIarguments\fP and \fIoptions\fP as if it had been invoked -directly. This largely eliminates possible name collisions with other software, -and also permits some centralized services. -.PP -All the commands described in this manual page are built-in and are used to -control and monitor IPsec connections as well as the IKE daemons. -.PP -For other commands -.I ipsec -supplies the invoked -.I command -with a suitable PATH environment variable, -and also provides IPSEC_DIR, -IPSEC_CONFS, and IPSEC_VERSION environment variables, -containing respectively -the full pathname of the directory where the IPsec utilities are stored, -the full pathname of the directory where the configuration files live, -and the IPsec version number. -.PP -.SS CONTROL COMMANDS -.TP -.B "ipsec start [ starter options ]" -calls -.BR "ipsec starter" -which in turn parses \fIipsec.conf\fR and starts the IKEv1 \fIpluto\fR and -IKEv2 \fIcharon\fR daemons. -.PP -.TP -.B "ipsec update" -sends a \fIHUP\fR signal to -.BR "ipsec starter" -which in turn determines any changes in \fIipsec.conf\fR -and updates the configuration on the running IKEv1 \fIpluto\fR and IKEv2 -\fIcharon\fR daemons, correspondingly. -.PP -.TP -.B "ipsec reload" -sends a \fIUSR1\fR signal to -.BR "ipsec starter" -which in turn reloads the whole configuration on the running IKEv1 \fIpluto\fR -and IKEv2 \fIcharon\fR daemons based on the actual \fIipsec.conf\fR. -.PP -.TP -.B "ipsec restart" -is equivalent to -.B "ipsec stop" -followed by -.B "ipsec start" -after a guard of 2 seconds. -.PP -.TP -.B "ipsec stop" -terminates all IPsec connections and stops the IKEv1 \fIpluto\fR and IKEv2 -\fIcharon\fR daemons by sending a \fITERM\fR signal to -.BR "ipsec starter". -.PP -.TP -.B "ipsec up \fIname\fP" -tells the responsible IKE daemon to start up connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname\fP" -tells the responsible IKE daemon to terminate connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname{n}\fP" -terminates IKEv2 CHILD SA instance \fIn\fP of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname{*}\fP" -terminates all IKEv2 CHILD SA instances of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname[n]\fP" -terminates all IKEv2 IKE SA instance \fIn\fP of connection \fIname\fP. -.PP -.TP -.B "ipsec down \fIname[*]\fP" -terminates all IKEv2 IKE SA instances of connection \fIname\fP. -.PP -.TP -.B "ipsec route \fIname\fP" -tells the responsible IKE daemon to insert an IPsec policy in the kernel -for connection \fIname\fP. The first payload packet matching the IPsec policy -will automatically trigger an IKE connection setup. -.PP -.TP -.B "ipsec unroute \fIname\fP" -remove the IPsec policy in the kernel for connection \fIname\fP. -.PP -.TP -.B "ipsec status [ \fIname\fP ]" -returns concise status information either on connection -\fIname\fP or if the argument is lacking, on all connections. -.PP -.TP -.B "ipsec statusall [ \fIname\fP ]" -returns detailed status information either on connection -\fIname\fP or if the argument is lacking, on all connections. -.PP -.SS LIST COMMANDS -.TP -.B "ipsec listalgs" -returns a list all supported IKE encryption and hash algorithms, the available -Diffie-Hellman groups, as well as all supported ESP encryption and -authentication algorithms registered via the Linux kernel's Crypto API. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listpubkeys [ --utc ]" -returns a list of RSA public keys that were either loaded in raw key format -or extracted from X.509 and|or OpenPGP certificates. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listcerts [ --utc ]" -returns a list of X.509 and|or OpenPGP certificates that were either loaded -locally by the IKE daemon or received via the IKEv2 protocol. -.PP -.TP -.B "ipsec listcacerts [ --utc ]" -returns a list of X.509 Certification Authority (CA) certificates that were -loaded locally by the IKE daemon from the \fI/etc/ipsec.d/cacerts/\fP -directory or received in PKCS#7-wrapped certificate payloads via the IKE -protocol. -.PP -.TP -.B "ipsec listaacerts [ --utc ]" -returns a list of X.509 Authorization Authority (AA) certificates that were -loaded locally by the IKE daemon from the \fI/etc/ipsec.d/aacerts/\fP -directory. -.PP -.TP -.B "ipsec listocspcerts [ --utc ]" -returns a list of X.509 OCSP Signer certificates that were either loaded -locally by the IKE daemon from the \fI/etc/ipsec.d/ocspcerts/\fP -directory or were sent by an OCSP server. -.PP -.TP -.B "ipsec listacerts [ --utc ]" -returns a list of X.509 Attribute certificates that were loaded locally by -the IKE daemon from the \fI/etc/ipsec.d/acerts/\fP directory. -.PP -.TP -.B "ipsec listgroups [ --utc ]" -returns a list of groups that are used to define user authorization profiles. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listcainfos [ --utc ]" -returns certification authority information (CRL distribution points, OCSP URIs, -LDAP servers) that were defined by -.BR ca -sections in \fIipsec.conf\fP. -.PP -.TP -.B "ipsec listcrls [ --utc ]" -returns a list of Certificate Revocation Lists (CRLs) that were either loaded -by the IKE daemon from the \fI/etc/ipsec.d/crls\fP directory or fetched from -an HTTP- or LDAP-based CRL distribution point. -.PP -.TP -.B "ipsec listocsp [ --utc ]" -returns revocation information fetched from OCSP servers. -.PP -.TP -.B "ipsec listcards [ --utc ]" -list all certificates found on attached smart cards. -.br -Supported by the IKEv1 \fIpluto\fP daemon only. -.PP -.TP -.B "ipsec listall [ --utc ]" -returns all information generated by the list commands above. Each list command -can be called with the -\fB\-\-utc\fP -option which displays all dates in UTC instead of local time. -.PP -.SS REREAD COMMANDS -.TP -.B "ipsec rereadsecrets" -flushes and rereads all secrets defined in \fIipsec.secrets\fP. -.PP -.TP -.B "ipsec rereadcacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP -directory and adds them to the list of Certification Authority (CA) -certificates. -.PP -.TP -.B "ipsec rereadaacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP -directory and adds them to the list of Authorization Authority (AA) -certificates. -.PP -.TP -.B "ipsec rereadocspcerts" -reads all certificate files contained in the \fI/etc/ipsec.d/ocspcerts/\fP -directory and adds them to the list of OCSP signer certificates. -.PP -.TP -.B "ipsec rereadacerts" -reads all certificate files contained in the \fI/etc/ipsec.d/acerts/\fP -directory and adds them to the list of attribute certificates. -.PP -.TP -.B "ipsec rereadcrls" -reads all Certificate Revocation Lists (CRLs) contained in the -\fI/etc/ipsec.d/crls/\fP directory and adds them to the list of CRLs. -.PP -.TP -.B "ipsec rereadall" -executes all reread commands listed above. -.PP -.SS PURGE COMMANDS -.TP -.B "ipsec purgeike" -purges IKEv2 SAs that don't have a CHILD SA. -.PP -.TP -.B "ipsec purgeocsp" -purges all cached OCSP information records. -.PP -.SS INFO COMMANDS -.TP -.B "ipsec \-\-help" -returns the usage information for the ipsec command. -.PP -.TP -.B "ipsec \-\-version" -returns the version in the form of -.B Linux strongSwan U/K -if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is -running on. -.PP -.TP -.B "ipsec \-\-versioncode" -returns the version number in the form of -.B U/K -if strongSwan uses the native NETKEY IPsec stack of the Linux kernel it is -running on. -.PP -.TP -.B "ipsec \-\-copyright" -returns the copyright information. -.PP -.TP -.B "ipsec \-\-directory" -returns the \fILIBEXECDIR\fP directory as defined by the configure options. -.PP -.TP -.B "ipsec \-\-confdir" -returns the \fISYSCONFDIR\fP directory as defined by the configure options. -.SH FILES -/usr/local/lib/ipsec usual utilities directory -.SH ENVIRONMENT -.PP -The following environment variables control where strongSwan finds its -components. -The -.B ipsec -command sets them if they are not already set. -.nf -.na - -IPSEC_DIR directory containing ipsec programs and utilities -IPSEC_SBINDIR directory containing \fBipsec\fP command -IPSEC_CONFDIR directory containing configuration files -IPSEC_PIDDIR directory containing PID files -IPSEC_NAME name of ipsec distribution -IPSEC_VERSION version numer of ipsec userland and kernel -IPSEC_STARTER_PID PID file for ipsec starter -IPSEC_PLUTO_PID PID file for IKEv1 keying daemon -IPSEC_CHARON_PID PID file for IKEv2 keying daemon -.ad -.fi -.SH SEE ALSO -.hy 0 -.na -ipsec.conf(5), ipsec.secrets(5) -.ad -.hy -.PP -.SH HISTORY -Originally written for the FreeS/WAN project by Henry Spencer. -Updated and extended for the strongSwan project by -Tobias Brunner and Andreas Steffen. diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in deleted file mode 100755 index 479974a0e..000000000 --- a/src/ipsec/ipsec.in +++ /dev/null @@ -1,408 +0,0 @@ -#! @IPSEC_SHELL@ -# prefix command to run stuff from our programs directory -# Copyright (C) 1998-2002 Henry Spencer. -# Copyright (C) 2006 Andreas Steffen -# Copyright (C) 2006 Martin Willi -# -# This program is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at your -# option) any later version. See . -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. - -# define a minimum PATH environment in case it is not set -PATH="/sbin:/bin:/usr/sbin:/usr/bin:@IPSEC_SBINDIR@" -export PATH - -# name and version of the ipsec implementation -OS_NAME=`uname -s` -IPSEC_NAME="@IPSEC_NAME@" -IPSEC_VERSION="U@IPSEC_VERSION@/K`uname -r`" - -# where the private directory and the config files are -IPSEC_DIR="@IPSEC_DIR@" -IPSEC_SBINDIR="@IPSEC_SBINDIR@" -IPSEC_CONFDIR="@IPSEC_CONFDIR@" -IPSEC_PIDDIR="@IPSEC_PIDDIR@" - -IPSEC_STARTER_PID="${IPSEC_PIDDIR}/starter.pid" -IPSEC_PLUTO_PID="${IPSEC_PIDDIR}/pluto.pid" -IPSEC_CHARON_PID="${IPSEC_PIDDIR}/charon.pid" - -IPSEC_WHACK="${IPSEC_DIR}/whack" -IPSEC_STROKE="${IPSEC_DIR}/stroke" -IPSEC_STARTER="${IPSEC_DIR}/starter" - -export IPSEC_DIR IPSEC_SBINDIR IPSEC_CONFDIR IPSEC_PIDDIR IPSEC_VERSION IPSEC_NAME IPSEC_STARTER_PID IPSEC_PLUTO_PID IPSEC_CHARON_PID - -IPSEC_DISTRO="Institute for Internet Technologies and Applications\nUniversity of Applied Sciences Rapperswil, Switzerland" - -case "$1" in -'') - echo "Usage: ipsec command argument ..." - echo "Use --help for list of commands, or see ipsec(8) manual page" - echo "or the $IPSEC_NAME documentation for names of the common ones." - echo "Most have their own manual pages, e.g. ipsec_auto(8)." - echo "See for more general info." - exit 0 - ;; ---help) - echo "Usage: ipsec command argument ..." - echo "where command is one of:" - echo " start|restart arguments..." - echo " update|reload|stop" - echo " up|down|route|unroute " - echo " status|statusall []" - echo " ready" - echo " listalgs|listpubkeys|listcerts [--utc]" - echo " listcacerts|listaacerts|listocspcerts [--utc]" - echo " listacerts|listgroups|listcainfos [--utc]" - echo " listcrls|listocsp|listcards|listplugins|listall [--utc]" - echo " leases [ [
]]" - echo " rereadsecrets|rereadgroups" - echo " rereadcacerts|rereadaacerts|rereadocspcerts" - echo " rereadacerts|rereadcrls|rereadall" - echo " purgeocsp|purgecrls|purgecerts|purgeike" - echo " scencrypt|scdecrypt [--inbase ] [--outbase ] [--keyid ]" - echo " openac" - echo " pluto" - echo " scepclient" - echo " secrets" - echo " starter" - echo " version" - echo " whack" - echo " stroke" - echo - echo "Some of these functions have their own manual pages, e.g. ipsec_scepclient(8)." - exit 0 - ;; ---versioncode) - echo "$IPSEC_VERSION" - exit 0 - ;; ---directory) - echo "$IPSEC_DIR" - exit 0 - ;; ---confdir) - echo "$IPSEC_CONFDIR" - exit 0 - ;; -copyright|--copyright) - set _copyright - # and fall through, invoking "ipsec _copyright" - ;; -down) - shift - if [ "$#" -ne 1 ] - then - echo "Usage: ipsec down " - exit 2 - fi - rc=7 - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --name "$1" --terminate - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE down "$1" - rc="$?" - fi - exit "$rc" - ;; -down-srcip) - shift - if [ "$#" -lt 1 ] - then - echo "Usage: ipsec down-srcip []" - exit 2 - fi - rc=7 - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE down-srcip $* - rc="$?" - fi - exit "$rc" - ;; -listcards|rereadgroups) - op="$1" - shift - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK "$@" "--$op" - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - exit 3 - else - exit 7 - fi - ;; -leases) - op="$1" - rc=7 - shift - if [ -e $IPSEC_PLUTO_PID ] - then - case "$#" in - 0) $IPSEC_WHACK "--$op" ;; - 1) $IPSEC_WHACK "--$op" --name "$1" ;; - *) $IPSEC_WHACK "--$op" --name "$1" --lease-addr "$2" ;; - esac - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - case "$#" in - 0) $IPSEC_STROKE "$op" ;; - 1) $IPSEC_STROKE "$op" "$1" ;; - *) $IPSEC_STROKE "$op" "$1" "$2" ;; - esac - rc="$?" - fi - exit "$rc" - ;; -listalgs|listpubkeys|listplugins|\ -listcerts|listcacerts|listaacerts|\ -listacerts|listgroups|listocspcerts|\ -listcainfos|listcrls|listocsp|listall|\ -rereadsecrets|rereadcacerts|rereadaacerts|\ -rereadacerts|rereadocspcerts|rereadcrls|\ -rereadall|purgeocsp) - op="$1" - rc=7 - shift - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK "$@" "--$op" - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE "$op" "$@" - rc="$?" - fi - exit "$rc" - ;; -purgeike|purgecrls|purgecerts) - rc=7 - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE "$1" - rc="$?" - fi - exit "$rc" - ;; -ready) - shift - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --listen - exit 0 - else - exit 7 - fi - ;; -reload) - rc=7 - if [ -e $IPSEC_STARTER_PID ] - then - echo "Reloading strongSwan IPsec configuration..." >&2 - kill -USR1 `cat $IPSEC_STARTER_PID` 2>/dev/null && rc=0 - else - echo "Reloading strongSwan IPsec failed: starter is not running" >&2 - fi - exit "$rc" - ;; -restart) - $IPSEC_SBINDIR/ipsec stop - sleep 2 - shift - exec $IPSEC_SBINDIR/ipsec start "$@" - ;; -route|unroute) - op="$1" - rc=7 - shift - if [ "$#" -ne 1 ] - then - echo "Usage: ipsec $op " - exit 2 - fi - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --name "$1" "--$op" - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE "$op" "$1" - rc="$?" - fi - exit "$rc" - ;; -scencrypt|scdecrypt) - op="$1" - shift - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK "--$op" "$@" - exit "$?" - else - exit 7 - fi - ;; -secrets) - rc=7 - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --rereadsecrets - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE rereadsecrets - rc="$?" - fi - exit "$rc" - ;; -start) - shift - if [ -d /var/lock/subsys ]; then - touch /var/lock/subsys/ipsec - fi - exec $IPSEC_STARTER "$@" - ;; -status|statusall) - op="$1" - # Return value is slightly different for the status command: - # 0 - service up and running - # 1 - service dead, but /var/run/ pid file exists - # 2 - service dead, but /var/lock/ lock file exists - # 3 - service not running (unused) - # 4 - service status unknown :-( - # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) - shift - if [ $# -eq 0 ] - then - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK "--$op" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE "$op" - fi - else - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --name "$1" "--$op" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE "$op" "$1" - fi - fi - if [ -e $IPSEC_STARTER_PID ] - then - kill -0 `cat $IPSEC_STARTER_PID` 2>/dev/null - exit $? - fi - exit 3 - ;; -stop) - # stopping a not-running service is considered as success - if [ -e $IPSEC_STARTER_PID ] - then - echo "Stopping strongSwan IPsec..." >&2 - spid=`cat $IPSEC_STARTER_PID` - if [ -n "$spid" ] - then - kill $spid 2>/dev/null - loop=11 - while [ $loop -gt 0 ] ; do - kill -0 $spid 2>/dev/null || break - sleep 1 - loop=$(($loop - 1)) - done - if [ $loop -eq 0 ] - then - kill -KILL $spid 2>/dev/null - rm -f $IPSEC_STARTER_PID - fi - fi - else - echo "Stopping strongSwan IPsec failed: starter is not running" >&2 - fi - if [ -d /var/lock/subsys ]; then - rm -f /var/lock/subsys/ipsec - fi - exit 0 - ;; -up) - shift - if [ "$#" -ne 1 ] - then - echo "Usage: ipsec up " - exit 2 - fi - rc=7 - if [ -e $IPSEC_PLUTO_PID ] - then - $IPSEC_WHACK --name "$1" --initiate - rc="$?" - fi - if [ -e $IPSEC_CHARON_PID ] - then - $IPSEC_STROKE up "$1" - rc="$?" - fi - exit "$rc" - ;; -update) - if [ -e $IPSEC_STARTER_PID ] - then - echo "Updating strongSwan IPsec configuration..." >&2 - kill -HUP `cat $IPSEC_STARTER_PID` - exit 0 - else - echo "Updating strongSwan IPsec failed: starter is not running" >&2 - exit 7 - fi - ;; -version|--version) - printf "$OS_NAME $IPSEC_NAME $IPSEC_VERSION\n" - printf "$IPSEC_DISTRO\n" - printf "See 'ipsec --copyright' for copyright information.\n" - exit 0 - ;; ---*) - echo "$0: unknown option \`$1' (perhaps command name was omitted?)" >&2 - exit 2 - ;; -esac - -cmd="$1" -shift - -path="$IPSEC_DIR/$cmd" - -if [ ! -x "$path" ] -then - path="$IPSEC_DIR/$cmd" - if [ ! -x "$path" ] - then - echo "$0: unknown IPsec command \`$cmd' (\`ipsec --help' for list)" >&2 - exit 2 - fi -fi - -exec $path "$@" diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk index f98d36a61..9eb864f50 100644 --- a/src/libcharon/Android.mk +++ b/src/libcharon/Android.mk @@ -5,6 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ bus/bus.c bus/bus.h \ bus/listeners/listener.h \ +bus/listeners/logger.h \ bus/listeners/file_logger.c bus/listeners/file_logger.h \ bus/listeners/sys_logger.c bus/listeners/sys_logger.h \ config/backend_manager.c config/backend_manager.h config/backend.h \ @@ -40,9 +41,10 @@ encoding/payloads/transform_substructure.c encoding/payloads/transform_substruct encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \ encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \ +encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \ kernel/kernel_handler.c kernel/kernel_handler.h \ network/receiver.c network/receiver.h network/sender.c network/sender.h \ -network/packet.c network/packet.h network/socket.c network/socket.h \ +network/socket.c network/socket.h \ network/socket_manager.c network/socket_manager.h \ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \ @@ -52,43 +54,73 @@ processing/jobs/process_message_job.c processing/jobs/process_message_job.h \ processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \ processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \ +processing/jobs/retry_initiate_job.c processing/jobs/retry_initiate_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ -sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ -sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ -sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ -sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ -sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ +sa/eap/eap_method.c sa/eap/eap_method.h \ +sa/eap/eap_manager.c sa/eap/eap_manager.h \ +sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ +sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ +sa/authenticator.c sa/authenticator.h \ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ +sa/keymat.h sa/keymat.c \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ -sa/task_manager.c sa/task_manager.h \ -sa/keymat.c sa/keymat.h \ +sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ -sa/tasks/child_create.c sa/tasks/child_create.h \ -sa/tasks/child_delete.c sa/tasks/child_delete.h \ -sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ -sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ -sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ -sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ -sa/tasks/ike_config.c sa/tasks/ike_config.h \ -sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ -sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ -sa/tasks/ike_init.c sa/tasks/ike_init.h \ -sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ -sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ -sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ -sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ -sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ -sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ -sa/tasks/task.c sa/tasks/task.h +sa/task.c sa/task.h + +LOCAL_SRC_FILES += \ +sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ +sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ +sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ +sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \ +sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \ +sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ +sa/ikev2/tasks/child_delete.c sa/ikev2/tasks/child_delete.h \ +sa/ikev2/tasks/child_rekey.c sa/ikev2/tasks/child_rekey.h \ +sa/ikev2/tasks/ike_auth.c sa/ikev2/tasks/ike_auth.h \ +sa/ikev2/tasks/ike_cert_pre.c sa/ikev2/tasks/ike_cert_pre.h \ +sa/ikev2/tasks/ike_cert_post.c sa/ikev2/tasks/ike_cert_post.h \ +sa/ikev2/tasks/ike_config.c sa/ikev2/tasks/ike_config.h \ +sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \ +sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \ +sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \ +sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \ +sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ +sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ +sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ +sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \ +sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h + +LOCAL_SRC_FILES += \ +sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \ +sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ +sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ +sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ +sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ +sa/ikev1/phase1.c sa/ikev1/phase1.h \ +sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ +sa/ikev1/tasks/aggressive_mode.c sa/ikev1/tasks/aggressive_mode.h \ +sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ +sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ +sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ +sa/ikev1/tasks/isakmp_natd.c sa/ikev1/tasks/isakmp_natd.h \ +sa/ikev1/tasks/isakmp_vendor.c sa/ikev1/tasks/isakmp_vendor.h \ +sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ +sa/ikev1/tasks/isakmp_dpd.c sa/ikev1/tasks/isakmp_dpd.h \ +sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ +sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ +sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ +sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h \ +processing/jobs/dpd_timeout_job.c processing/jobs/dpd_timeout_job.h \ +processing/jobs/adopt_children_job.c processing/jobs/adopt_children_job.h # adding the plugin source files @@ -98,6 +130,11 @@ LOCAL_C_INCLUDES += frameworks/base/cmds/keystore LOCAL_SHARED_LIBRARIES += libcutils endif +LOCAL_SRC_FILES += $(call add_plugin, android-log) +ifneq ($(call plugin_enabled, android-log),) +LOCAL_LDLIBS += -llog +endif + LOCAL_SRC_FILES += $(call add_plugin, attr) LOCAL_SRC_FILES += $(call add_plugin, eap-aka) @@ -137,14 +174,32 @@ LOCAL_SRC_FILES += $(addprefix ../libsimaka/, \ ) endif +LOCAL_SRC_FILES += $(call add_plugin, eap-tls) + +LOCAL_SRC_FILES += $(call add_plugin, eap-ttls) +ifneq ($(call plugin_enabled, eap-ttls),) +# for radius_message.h +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libradius/ +endif + +LOCAL_SRC_FILES += $(call add_plugin, eap-peap) + +# adding libtls if any of the three plugins above is enabled +ifneq ($(or $(call plugin_enabled, eap-tls), $(call plugin_enabled, eap-ttls), $(call plugin_enabled, eap-peap)),) +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/ +LOCAL_SRC_FILES += $(addprefix ../libtls/, \ + tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \ + tls_crypto.c tls_prf.c tls_socket.c tls_eap.c tls_cache.c tls_peer.c \ + tls_server.c tls.c \ + ) +endif + LOCAL_SRC_FILES += $(call add_plugin, load-tester) LOCAL_SRC_FILES += $(call add_plugin, socket-default) LOCAL_SRC_FILES += $(call add_plugin, socket-dynamic) -LOCAL_SRC_FILES += $(call add_plugin, socket-raw) - LOCAL_SRC_FILES += $(call add_plugin, stroke) ifneq ($(call plugin_enabled, stroke),) LOCAL_C_INCLUDES += $(LOCAL_PATH)/../stroke/ @@ -160,8 +215,7 @@ LOCAL_C_INCLUDES += \ $(strongswan_PATH)/src/libstrongswan \ $(strongswan_PATH)/src/libtncif -LOCAL_CFLAGS := $(strongswan_CFLAGS) \ - -DPLUGINS='"$(strongswan_CHARON_PLUGINS)"' +LOCAL_CFLAGS := $(strongswan_CFLAGS) LOCAL_MODULE := libcharon diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index b86bd428c..56192bf0e 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -3,6 +3,7 @@ ipseclib_LTLIBRARIES = libcharon.la libcharon_la_SOURCES = \ bus/bus.c bus/bus.h \ bus/listeners/listener.h \ +bus/listeners/logger.h \ bus/listeners/file_logger.c bus/listeners/file_logger.h \ bus/listeners/sys_logger.c bus/listeners/sys_logger.h \ config/backend_manager.c config/backend_manager.h config/backend.h \ @@ -38,9 +39,10 @@ encoding/payloads/transform_substructure.c encoding/payloads/transform_substruct encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \ encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \ +encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \ kernel/kernel_handler.c kernel/kernel_handler.h \ network/receiver.c network/receiver.h network/sender.c network/sender.h \ -network/packet.c network/packet.h network/socket.c network/socket.h \ +network/socket.c network/socket.h \ network/socket_manager.c network/socket_manager.h \ processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \ @@ -50,43 +52,78 @@ processing/jobs/process_message_job.c processing/jobs/process_message_job.h \ processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \ processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \ +processing/jobs/retry_initiate_job.c processing/jobs/retry_initiate_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ -sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ -sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ -sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ -sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ -sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ +sa/eap/eap_method.c sa/eap/eap_method.h \ +sa/eap/eap_manager.c sa/eap/eap_manager.h \ +sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ +sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ +sa/authenticator.c sa/authenticator.h \ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ +sa/keymat.h sa/keymat.c \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ -sa/task_manager.c sa/task_manager.h \ -sa/keymat.c sa/keymat.h \ +sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ -sa/tasks/child_create.c sa/tasks/child_create.h \ -sa/tasks/child_delete.c sa/tasks/child_delete.h \ -sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ -sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ -sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ -sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ -sa/tasks/ike_config.c sa/tasks/ike_config.h \ -sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ -sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ -sa/tasks/ike_init.c sa/tasks/ike_init.h \ -sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ -sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ -sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ -sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ -sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ -sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ -sa/tasks/task.c sa/tasks/task.h +sa/task.c sa/task.h + +if USE_IKEV2 +libcharon_la_SOURCES += \ +sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ +sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ +sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ +sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \ +sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \ +sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ +sa/ikev2/tasks/child_delete.c sa/ikev2/tasks/child_delete.h \ +sa/ikev2/tasks/child_rekey.c sa/ikev2/tasks/child_rekey.h \ +sa/ikev2/tasks/ike_auth.c sa/ikev2/tasks/ike_auth.h \ +sa/ikev2/tasks/ike_cert_pre.c sa/ikev2/tasks/ike_cert_pre.h \ +sa/ikev2/tasks/ike_cert_post.c sa/ikev2/tasks/ike_cert_post.h \ +sa/ikev2/tasks/ike_config.c sa/ikev2/tasks/ike_config.h \ +sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \ +sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \ +sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \ +sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \ +sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ +sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ +sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ +sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \ +sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h +endif + +if USE_IKEV1 +libcharon_la_SOURCES += \ +sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \ +sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ +sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ +sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ +sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ +sa/ikev1/phase1.c sa/ikev1/phase1.h \ +sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ +sa/ikev1/tasks/aggressive_mode.c sa/ikev1/tasks/aggressive_mode.h \ +sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ +sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ +sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ +sa/ikev1/tasks/isakmp_natd.c sa/ikev1/tasks/isakmp_natd.h \ +sa/ikev1/tasks/isakmp_vendor.c sa/ikev1/tasks/isakmp_vendor.h \ +sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ +sa/ikev1/tasks/isakmp_dpd.c sa/ikev1/tasks/isakmp_dpd.h \ +sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ +sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ +sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ +sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h \ +processing/jobs/dpd_timeout_job.c processing/jobs/dpd_timeout_job.h \ +processing/jobs/adopt_children_job.c processing/jobs/adopt_children_job.h +endif + daemon.lo : $(top_builddir)/config.status @@ -98,8 +135,7 @@ INCLUDES = \ AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_PIDDIR=\"${piddir}\" \ - -DPLUGINS=\""${libcharon_plugins}\"" + -DIPSEC_PIDDIR=\"${piddir}\" libcharon_la_LIBADD = -lm $(PTHREADLIB) $(DLLIB) $(SOCKLIB) @@ -112,13 +148,9 @@ if USE_ME libcharon_la_SOURCES += encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \ processing/jobs/mediation_job.c processing/jobs/mediation_job.h \ - sa/connect_manager.c sa/connect_manager.h \ - sa/mediation_manager.c sa/mediation_manager.h \ - sa/tasks/ike_me.c sa/tasks/ike_me.h -endif - -if USE_LIBCAP - libcharon_la_LIBADD += -lcap + sa/ikev2/connect_manager.c sa/ikev2/connect_manager.h \ + sa/ikev2/mediation_manager.c sa/ikev2/mediation_manager.h \ + sa/ikev2/tasks/ike_me.c sa/ikev2/tasks/ike_me.h endif # build optional plugins @@ -144,13 +176,6 @@ if MONOLITHIC endif endif -if USE_SOCKET_RAW - SUBDIRS += plugins/socket_raw -if MONOLITHIC - libcharon_la_LIBADD += plugins/socket_raw/libstrongswan-socket-raw.la -endif -endif - if USE_SOCKET_DYNAMIC SUBDIRS += plugins/socket_dynamic if MONOLITHIC @@ -284,6 +309,13 @@ if MONOLITHIC endif endif +if USE_EAP_DYNAMIC + SUBDIRS += plugins/eap_dynamic +if MONOLITHIC + libcharon_la_LIBADD += plugins/eap_dynamic/libstrongswan-eap-dynamic.la +endif +endif + if USE_EAP_RADIUS SUBDIRS += plugins/eap_radius if MONOLITHIC @@ -410,13 +442,6 @@ if MONOLITHIC endif endif -if USE_NM - SUBDIRS += plugins/nm -if MONOLITHIC - libcharon_la_LIBADD += plugins/nm/libstrongswan-nm.la -endif -endif - if USE_DHCP SUBDIRS += plugins/dhcp if MONOLITHIC @@ -431,6 +456,13 @@ if MONOLITHIC endif endif +if USE_ANDROID_LOG + SUBDIRS += plugins/android_log +if MONOLITHIC + libcharon_la_LIBADD += plugins/android_log/libstrongswan-android-log.la +endif +endif + if USE_MAEMO SUBDIRS += plugins/maemo if MONOLITHIC @@ -497,7 +529,14 @@ endif if USE_ADDRBLOCK SUBDIRS += plugins/addrblock if MONOLITHIC - libcharon_la_LIBADD += plugins/uci/libstrongswan-addrblock.la + libcharon_la_LIBADD += plugins/addrblock/libstrongswan-addrblock.la +endif +endif + +if USE_UNITY + SUBDIRS += plugins/unity +if MONOLITHIC + libcharon_la_LIBADD += plugins/unity/libstrongswan-unity.la endif endif @@ -508,3 +547,23 @@ if MONOLITHIC endif endif +if USE_XAUTH_GENERIC + SUBDIRS += plugins/xauth_generic +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_generic/libstrongswan-xauth-generic.la +endif +endif + +if USE_XAUTH_EAP + SUBDIRS += plugins/xauth_eap +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_eap/libstrongswan-xauth-eap.la +endif +endif + +if USE_XAUTH_PAM + SUBDIRS += plugins/xauth_pam +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_pam/libstrongswan-xauth-pam.la +endif +endif diff --git a/src/libcharon/Makefile.in b/src/libcharon/Makefile.in index ccbd4add2..3a9239af3 100644 --- a/src/libcharon/Makefile.in +++ b/src/libcharon/Makefile.in @@ -34,121 +34,174 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +@USE_IKEV2_TRUE@am__append_1 = \ +@USE_IKEV2_TRUE@sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ +@USE_IKEV2_TRUE@sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ +@USE_IKEV2_TRUE@sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ +@USE_IKEV2_TRUE@sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \ +@USE_IKEV2_TRUE@sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/child_delete.c sa/ikev2/tasks/child_delete.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/child_rekey.c sa/ikev2/tasks/child_rekey.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_auth.c sa/ikev2/tasks/ike_auth.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_cert_pre.c sa/ikev2/tasks/ike_cert_pre.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_cert_post.c sa/ikev2/tasks/ike_cert_post.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_config.c sa/ikev2/tasks/ike_config.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \ +@USE_IKEV2_TRUE@sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h + +@USE_IKEV1_TRUE@am__append_2 = \ +@USE_IKEV1_TRUE@sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \ +@USE_IKEV1_TRUE@sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ +@USE_IKEV1_TRUE@sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ +@USE_IKEV1_TRUE@sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ +@USE_IKEV1_TRUE@sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ +@USE_IKEV1_TRUE@sa/ikev1/phase1.c sa/ikev1/phase1.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/aggressive_mode.c sa/ikev1/tasks/aggressive_mode.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_natd.c sa/ikev1/tasks/isakmp_natd.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_vendor.c sa/ikev1/tasks/isakmp_vendor.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/isakmp_dpd.c sa/ikev1/tasks/isakmp_dpd.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ +@USE_IKEV1_TRUE@sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h \ +@USE_IKEV1_TRUE@processing/jobs/dpd_timeout_job.c processing/jobs/dpd_timeout_job.h \ +@USE_IKEV1_TRUE@processing/jobs/adopt_children_job.c processing/jobs/adopt_children_job.h + # compile options ################# -@USE_ME_TRUE@am__append_1 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ +@USE_ME_TRUE@am__append_3 = encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ @USE_ME_TRUE@ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \ @USE_ME_TRUE@ processing/jobs/mediation_job.c processing/jobs/mediation_job.h \ -@USE_ME_TRUE@ sa/connect_manager.c sa/connect_manager.h \ -@USE_ME_TRUE@ sa/mediation_manager.c sa/mediation_manager.h \ -@USE_ME_TRUE@ sa/tasks/ike_me.c sa/tasks/ike_me.h - -@USE_LIBCAP_TRUE@am__append_2 = -lcap -@USE_LOAD_TESTER_TRUE@am__append_3 = plugins/load_tester -@MONOLITHIC_TRUE@@USE_LOAD_TESTER_TRUE@am__append_4 = plugins/load_tester/libstrongswan-load-tester.la -@USE_SOCKET_DEFAULT_TRUE@am__append_5 = plugins/socket_default -@MONOLITHIC_TRUE@@USE_SOCKET_DEFAULT_TRUE@am__append_6 = plugins/socket_default/libstrongswan-socket-default.la -@USE_SOCKET_RAW_TRUE@am__append_7 = plugins/socket_raw -@MONOLITHIC_TRUE@@USE_SOCKET_RAW_TRUE@am__append_8 = plugins/socket_raw/libstrongswan-socket-raw.la -@USE_SOCKET_DYNAMIC_TRUE@am__append_9 = plugins/socket_dynamic -@MONOLITHIC_TRUE@@USE_SOCKET_DYNAMIC_TRUE@am__append_10 = plugins/socket_dynamic/libstrongswan-socket-dynamic.la -@USE_FARP_TRUE@am__append_11 = plugins/farp -@MONOLITHIC_TRUE@@USE_FARP_TRUE@am__append_12 = plugins/farp/libstrongswan-farp.la -@USE_STROKE_TRUE@am__append_13 = plugins/stroke -@MONOLITHIC_TRUE@@USE_STROKE_TRUE@am__append_14 = plugins/stroke/libstrongswan-stroke.la -@USE_SMP_TRUE@am__append_15 = plugins/smp -@MONOLITHIC_TRUE@@USE_SMP_TRUE@am__append_16 = plugins/smp/libstrongswan-smp.la -@USE_SQL_TRUE@am__append_17 = plugins/sql -@MONOLITHIC_TRUE@@USE_SQL_TRUE@am__append_18 = plugins/sql/libstrongswan-sql.la -@USE_UPDOWN_TRUE@am__append_19 = plugins/updown -@MONOLITHIC_TRUE@@USE_UPDOWN_TRUE@am__append_20 = plugins/updown/libstrongswan-updown.la -@USE_EAP_IDENTITY_TRUE@am__append_21 = plugins/eap_identity -@MONOLITHIC_TRUE@@USE_EAP_IDENTITY_TRUE@am__append_22 = plugins/eap_identity/libstrongswan-eap-identity.la -@USE_EAP_SIM_TRUE@am__append_23 = plugins/eap_sim -@MONOLITHIC_TRUE@@USE_EAP_SIM_TRUE@am__append_24 = plugins/eap_sim/libstrongswan-eap-sim.la -@USE_EAP_SIM_FILE_TRUE@am__append_25 = plugins/eap_sim_file -@MONOLITHIC_TRUE@@USE_EAP_SIM_FILE_TRUE@am__append_26 = plugins/eap_sim_file/libstrongswan-eap-sim-file.la -@USE_EAP_SIM_PCSC_TRUE@am__append_27 = plugins/eap_sim_pcsc -@MONOLITHIC_TRUE@@USE_EAP_SIM_PCSC_TRUE@am__append_28 = plugins/eap_sim_pcsc/libstrongswan-eap-sim-pcsc.la -@USE_EAP_SIMAKA_SQL_TRUE@am__append_29 = plugins/eap_simaka_sql -@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_SQL_TRUE@am__append_30 = plugins/eap_simaka_sql/libstrongswan-eap-simaka-sql.la -@USE_EAP_SIMAKA_PSEUDONYM_TRUE@am__append_31 = plugins/eap_simaka_pseudonym -@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_PSEUDONYM_TRUE@am__append_32 = plugins/eap_simaka_pseudonym/libstrongswan-eap-simaka-pseudonym.la -@USE_EAP_SIMAKA_REAUTH_TRUE@am__append_33 = plugins/eap_simaka_reauth -@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_REAUTH_TRUE@am__append_34 = plugins/eap_simaka_reauth/libstrongswan-eap-simaka-reauth.la -@USE_EAP_AKA_TRUE@am__append_35 = plugins/eap_aka -@MONOLITHIC_TRUE@@USE_EAP_AKA_TRUE@am__append_36 = plugins/eap_aka/libstrongswan-eap-aka.la -@USE_EAP_AKA_3GPP2_TRUE@am__append_37 = plugins/eap_aka_3gpp2 -@MONOLITHIC_TRUE@@USE_EAP_AKA_3GPP2_TRUE@am__append_38 = plugins/eap_aka_3gpp2/libstrongswan-eap-aka-3gpp2.la -@MONOLITHIC_TRUE@@USE_SIMAKA_TRUE@am__append_39 = $(top_builddir)/src/libsimaka/libsimaka.la -@USE_EAP_MD5_TRUE@am__append_40 = plugins/eap_md5 -@MONOLITHIC_TRUE@@USE_EAP_MD5_TRUE@am__append_41 = plugins/eap_md5/libstrongswan-eap-md5.la -@USE_EAP_GTC_TRUE@am__append_42 = plugins/eap_gtc -@MONOLITHIC_TRUE@@USE_EAP_GTC_TRUE@am__append_43 = plugins/eap_gtc/libstrongswan-eap-gtc.la -@USE_EAP_MSCHAPV2_TRUE@am__append_44 = plugins/eap_mschapv2 -@MONOLITHIC_TRUE@@USE_EAP_MSCHAPV2_TRUE@am__append_45 = plugins/eap_mschapv2/libstrongswan-eap-mschapv2.la -@USE_EAP_RADIUS_TRUE@am__append_46 = plugins/eap_radius -@MONOLITHIC_TRUE@@USE_EAP_RADIUS_TRUE@am__append_47 = plugins/eap_radius/libstrongswan-eap-radius.la -@USE_EAP_TLS_TRUE@am__append_48 = plugins/eap_tls -@MONOLITHIC_TRUE@@USE_EAP_TLS_TRUE@am__append_49 = plugins/eap_tls/libstrongswan-eap-tls.la -@USE_EAP_TTLS_TRUE@am__append_50 = plugins/eap_ttls -@MONOLITHIC_TRUE@@USE_EAP_TTLS_TRUE@am__append_51 = plugins/eap_ttls/libstrongswan-eap-ttls.la -@USE_EAP_PEAP_TRUE@am__append_52 = plugins/eap_peap -@MONOLITHIC_TRUE@@USE_EAP_PEAP_TRUE@am__append_53 = plugins/eap_peap/libstrongswan-eap-peap.la -@USE_EAP_TNC_TRUE@am__append_54 = plugins/eap_tnc -@MONOLITHIC_TRUE@@USE_EAP_TNC_TRUE@am__append_55 = plugins/eap_tnc/libstrongswan-eap-tnc.la -@MONOLITHIC_TRUE@@USE_TLS_TRUE@am__append_56 = $(top_builddir)/src/libtls/libtls.la -@MONOLITHIC_TRUE@@USE_RADIUS_TRUE@am__append_57 = $(top_builddir)/src/libradius/libradius.la -@USE_TNC_IFMAP_TRUE@am__append_58 = plugins/tnc_ifmap -@MONOLITHIC_TRUE@@USE_TNC_IFMAP_TRUE@am__append_59 = plugins/tnc_ifmap/libstrongswan-tnc-ifmap.la -@USE_TNC_PDP_TRUE@am__append_60 = plugins/tnc_pdp -@MONOLITHIC_TRUE@@USE_TNC_PDP_TRUE@am__append_61 = plugins/tnc_pdp/libstrongswan-tnc-pdp.la -@USE_TNC_IMC_TRUE@am__append_62 = plugins/tnc_imc -@MONOLITHIC_TRUE@@USE_TNC_IMC_TRUE@am__append_63 = plugins/tnc_imc/libstrongswan-tnc-imc.la -@USE_TNC_IMV_TRUE@am__append_64 = plugins/tnc_imv -@MONOLITHIC_TRUE@@USE_TNC_IMV_TRUE@am__append_65 = plugins/tnc_imv/libstrongswan-tnc-imv.la -@USE_TNC_TNCCS_TRUE@am__append_66 = plugins/tnc_tnccs -@MONOLITHIC_TRUE@@USE_TNC_TNCCS_TRUE@am__append_67 = plugins/tnc_tnccs/libstrongswan-tnc-tnccs.la -@USE_TNCCS_11_TRUE@am__append_68 = plugins/tnccs_11 -@MONOLITHIC_TRUE@@USE_TNCCS_11_TRUE@am__append_69 = plugins/tnccs_11/libstrongswan-tnccs-11.la -@USE_TNCCS_20_TRUE@am__append_70 = plugins/tnccs_20 -@MONOLITHIC_TRUE@@USE_TNCCS_20_TRUE@am__append_71 = plugins/tnccs_20/libstrongswan-tnccs-20.la -@USE_TNCCS_DYNAMIC_TRUE@am__append_72 = plugins/tnccs_dynamic -@MONOLITHIC_TRUE@@USE_TNCCS_DYNAMIC_TRUE@am__append_73 = plugins/tnccs_dynamic/libstrongswan-tnccs-dynamic.la -@MONOLITHIC_TRUE@@USE_LIBTNCCS_TRUE@am__append_74 = $(top_builddir)/src/libtnccs/libtnccs.la -@USE_MEDSRV_TRUE@am__append_75 = plugins/medsrv -@MONOLITHIC_TRUE@@USE_MEDSRV_TRUE@am__append_76 = plugins/medsrv/libstrongswan-medsrv.la -@USE_MEDCLI_TRUE@am__append_77 = plugins/medcli -@MONOLITHIC_TRUE@@USE_MEDCLI_TRUE@am__append_78 = plugins/medcli/libstrongswan-medcli.la -@USE_NM_TRUE@am__append_79 = plugins/nm -@MONOLITHIC_TRUE@@USE_NM_TRUE@am__append_80 = plugins/nm/libstrongswan-nm.la -@USE_DHCP_TRUE@am__append_81 = plugins/dhcp -@MONOLITHIC_TRUE@@USE_DHCP_TRUE@am__append_82 = plugins/dhcp/libstrongswan-dhcp.la -@USE_ANDROID_TRUE@am__append_83 = plugins/android -@MONOLITHIC_TRUE@@USE_ANDROID_TRUE@am__append_84 = plugins/android/libstrongswan-android.la -@USE_MAEMO_TRUE@am__append_85 = plugins/maemo -@MONOLITHIC_TRUE@@USE_MAEMO_TRUE@am__append_86 = plugins/maemo/libstrongswan-maemo.la -@USE_HA_TRUE@am__append_87 = plugins/ha -@MONOLITHIC_TRUE@@USE_HA_TRUE@am__append_88 = plugins/ha/libstrongswan-ha.la -@USE_WHITELIST_TRUE@am__append_89 = plugins/whitelist -@MONOLITHIC_TRUE@@USE_WHITELIST_TRUE@am__append_90 = plugins/whitelist/libstrongswan-whitelist.la -@USE_CERTEXPIRE_TRUE@am__append_91 = plugins/certexpire -@MONOLITHIC_TRUE@@USE_CERTEXPIRE_TRUE@am__append_92 = plugins/certexpire/libstrongswan-certexpire.la -@USE_LED_TRUE@am__append_93 = plugins/led -@MONOLITHIC_TRUE@@USE_LED_TRUE@am__append_94 = plugins/led/libstrongswan-led.la -@USE_DUPLICHECK_TRUE@am__append_95 = plugins/duplicheck -@MONOLITHIC_TRUE@@USE_DUPLICHECK_TRUE@am__append_96 = plugins/duplicheck/libstrongswan-duplicheck.la -@USE_COUPLING_TRUE@am__append_97 = plugins/coupling -@MONOLITHIC_TRUE@@USE_COUPLING_TRUE@am__append_98 = plugins/coupling/libstrongswan-coupling.la -@USE_RADATTR_TRUE@am__append_99 = plugins/radattr -@MONOLITHIC_TRUE@@USE_RADATTR_TRUE@am__append_100 = plugins/radattr/libstrongswan-radattr.la -@USE_UCI_TRUE@am__append_101 = plugins/uci -@MONOLITHIC_TRUE@@USE_UCI_TRUE@am__append_102 = plugins/uci/libstrongswan-uci.la -@USE_ADDRBLOCK_TRUE@am__append_103 = plugins/addrblock -@MONOLITHIC_TRUE@@USE_ADDRBLOCK_TRUE@am__append_104 = plugins/uci/libstrongswan-addrblock.la -@USE_UNIT_TESTS_TRUE@am__append_105 = plugins/unit_tester -@MONOLITHIC_TRUE@@USE_UNIT_TESTS_TRUE@am__append_106 = plugins/unit_tester/libstrongswan-unit-tester.la +@USE_ME_TRUE@ sa/ikev2/connect_manager.c sa/ikev2/connect_manager.h \ +@USE_ME_TRUE@ sa/ikev2/mediation_manager.c sa/ikev2/mediation_manager.h \ +@USE_ME_TRUE@ sa/ikev2/tasks/ike_me.c sa/ikev2/tasks/ike_me.h + +@USE_LOAD_TESTER_TRUE@am__append_4 = plugins/load_tester +@MONOLITHIC_TRUE@@USE_LOAD_TESTER_TRUE@am__append_5 = plugins/load_tester/libstrongswan-load-tester.la +@USE_SOCKET_DEFAULT_TRUE@am__append_6 = plugins/socket_default +@MONOLITHIC_TRUE@@USE_SOCKET_DEFAULT_TRUE@am__append_7 = plugins/socket_default/libstrongswan-socket-default.la +@USE_SOCKET_DYNAMIC_TRUE@am__append_8 = plugins/socket_dynamic +@MONOLITHIC_TRUE@@USE_SOCKET_DYNAMIC_TRUE@am__append_9 = plugins/socket_dynamic/libstrongswan-socket-dynamic.la +@USE_FARP_TRUE@am__append_10 = plugins/farp +@MONOLITHIC_TRUE@@USE_FARP_TRUE@am__append_11 = plugins/farp/libstrongswan-farp.la +@USE_STROKE_TRUE@am__append_12 = plugins/stroke +@MONOLITHIC_TRUE@@USE_STROKE_TRUE@am__append_13 = plugins/stroke/libstrongswan-stroke.la +@USE_SMP_TRUE@am__append_14 = plugins/smp +@MONOLITHIC_TRUE@@USE_SMP_TRUE@am__append_15 = plugins/smp/libstrongswan-smp.la +@USE_SQL_TRUE@am__append_16 = plugins/sql +@MONOLITHIC_TRUE@@USE_SQL_TRUE@am__append_17 = plugins/sql/libstrongswan-sql.la +@USE_UPDOWN_TRUE@am__append_18 = plugins/updown +@MONOLITHIC_TRUE@@USE_UPDOWN_TRUE@am__append_19 = plugins/updown/libstrongswan-updown.la +@USE_EAP_IDENTITY_TRUE@am__append_20 = plugins/eap_identity +@MONOLITHIC_TRUE@@USE_EAP_IDENTITY_TRUE@am__append_21 = plugins/eap_identity/libstrongswan-eap-identity.la +@USE_EAP_SIM_TRUE@am__append_22 = plugins/eap_sim +@MONOLITHIC_TRUE@@USE_EAP_SIM_TRUE@am__append_23 = plugins/eap_sim/libstrongswan-eap-sim.la +@USE_EAP_SIM_FILE_TRUE@am__append_24 = plugins/eap_sim_file +@MONOLITHIC_TRUE@@USE_EAP_SIM_FILE_TRUE@am__append_25 = plugins/eap_sim_file/libstrongswan-eap-sim-file.la +@USE_EAP_SIM_PCSC_TRUE@am__append_26 = plugins/eap_sim_pcsc +@MONOLITHIC_TRUE@@USE_EAP_SIM_PCSC_TRUE@am__append_27 = plugins/eap_sim_pcsc/libstrongswan-eap-sim-pcsc.la +@USE_EAP_SIMAKA_SQL_TRUE@am__append_28 = plugins/eap_simaka_sql +@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_SQL_TRUE@am__append_29 = plugins/eap_simaka_sql/libstrongswan-eap-simaka-sql.la +@USE_EAP_SIMAKA_PSEUDONYM_TRUE@am__append_30 = plugins/eap_simaka_pseudonym +@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_PSEUDONYM_TRUE@am__append_31 = plugins/eap_simaka_pseudonym/libstrongswan-eap-simaka-pseudonym.la +@USE_EAP_SIMAKA_REAUTH_TRUE@am__append_32 = plugins/eap_simaka_reauth +@MONOLITHIC_TRUE@@USE_EAP_SIMAKA_REAUTH_TRUE@am__append_33 = plugins/eap_simaka_reauth/libstrongswan-eap-simaka-reauth.la +@USE_EAP_AKA_TRUE@am__append_34 = plugins/eap_aka +@MONOLITHIC_TRUE@@USE_EAP_AKA_TRUE@am__append_35 = plugins/eap_aka/libstrongswan-eap-aka.la +@USE_EAP_AKA_3GPP2_TRUE@am__append_36 = plugins/eap_aka_3gpp2 +@MONOLITHIC_TRUE@@USE_EAP_AKA_3GPP2_TRUE@am__append_37 = plugins/eap_aka_3gpp2/libstrongswan-eap-aka-3gpp2.la +@MONOLITHIC_TRUE@@USE_SIMAKA_TRUE@am__append_38 = $(top_builddir)/src/libsimaka/libsimaka.la +@USE_EAP_MD5_TRUE@am__append_39 = plugins/eap_md5 +@MONOLITHIC_TRUE@@USE_EAP_MD5_TRUE@am__append_40 = plugins/eap_md5/libstrongswan-eap-md5.la +@USE_EAP_GTC_TRUE@am__append_41 = plugins/eap_gtc +@MONOLITHIC_TRUE@@USE_EAP_GTC_TRUE@am__append_42 = plugins/eap_gtc/libstrongswan-eap-gtc.la +@USE_EAP_MSCHAPV2_TRUE@am__append_43 = plugins/eap_mschapv2 +@MONOLITHIC_TRUE@@USE_EAP_MSCHAPV2_TRUE@am__append_44 = plugins/eap_mschapv2/libstrongswan-eap-mschapv2.la +@USE_EAP_DYNAMIC_TRUE@am__append_45 = plugins/eap_dynamic +@MONOLITHIC_TRUE@@USE_EAP_DYNAMIC_TRUE@am__append_46 = plugins/eap_dynamic/libstrongswan-eap-dynamic.la +@USE_EAP_RADIUS_TRUE@am__append_47 = plugins/eap_radius +@MONOLITHIC_TRUE@@USE_EAP_RADIUS_TRUE@am__append_48 = plugins/eap_radius/libstrongswan-eap-radius.la +@USE_EAP_TLS_TRUE@am__append_49 = plugins/eap_tls +@MONOLITHIC_TRUE@@USE_EAP_TLS_TRUE@am__append_50 = plugins/eap_tls/libstrongswan-eap-tls.la +@USE_EAP_TTLS_TRUE@am__append_51 = plugins/eap_ttls +@MONOLITHIC_TRUE@@USE_EAP_TTLS_TRUE@am__append_52 = plugins/eap_ttls/libstrongswan-eap-ttls.la +@USE_EAP_PEAP_TRUE@am__append_53 = plugins/eap_peap +@MONOLITHIC_TRUE@@USE_EAP_PEAP_TRUE@am__append_54 = plugins/eap_peap/libstrongswan-eap-peap.la +@USE_EAP_TNC_TRUE@am__append_55 = plugins/eap_tnc +@MONOLITHIC_TRUE@@USE_EAP_TNC_TRUE@am__append_56 = plugins/eap_tnc/libstrongswan-eap-tnc.la +@MONOLITHIC_TRUE@@USE_TLS_TRUE@am__append_57 = $(top_builddir)/src/libtls/libtls.la +@MONOLITHIC_TRUE@@USE_RADIUS_TRUE@am__append_58 = $(top_builddir)/src/libradius/libradius.la +@USE_TNC_IFMAP_TRUE@am__append_59 = plugins/tnc_ifmap +@MONOLITHIC_TRUE@@USE_TNC_IFMAP_TRUE@am__append_60 = plugins/tnc_ifmap/libstrongswan-tnc-ifmap.la +@USE_TNC_PDP_TRUE@am__append_61 = plugins/tnc_pdp +@MONOLITHIC_TRUE@@USE_TNC_PDP_TRUE@am__append_62 = plugins/tnc_pdp/libstrongswan-tnc-pdp.la +@USE_TNC_IMC_TRUE@am__append_63 = plugins/tnc_imc +@MONOLITHIC_TRUE@@USE_TNC_IMC_TRUE@am__append_64 = plugins/tnc_imc/libstrongswan-tnc-imc.la +@USE_TNC_IMV_TRUE@am__append_65 = plugins/tnc_imv +@MONOLITHIC_TRUE@@USE_TNC_IMV_TRUE@am__append_66 = plugins/tnc_imv/libstrongswan-tnc-imv.la +@USE_TNC_TNCCS_TRUE@am__append_67 = plugins/tnc_tnccs +@MONOLITHIC_TRUE@@USE_TNC_TNCCS_TRUE@am__append_68 = plugins/tnc_tnccs/libstrongswan-tnc-tnccs.la +@USE_TNCCS_11_TRUE@am__append_69 = plugins/tnccs_11 +@MONOLITHIC_TRUE@@USE_TNCCS_11_TRUE@am__append_70 = plugins/tnccs_11/libstrongswan-tnccs-11.la +@USE_TNCCS_20_TRUE@am__append_71 = plugins/tnccs_20 +@MONOLITHIC_TRUE@@USE_TNCCS_20_TRUE@am__append_72 = plugins/tnccs_20/libstrongswan-tnccs-20.la +@USE_TNCCS_DYNAMIC_TRUE@am__append_73 = plugins/tnccs_dynamic +@MONOLITHIC_TRUE@@USE_TNCCS_DYNAMIC_TRUE@am__append_74 = plugins/tnccs_dynamic/libstrongswan-tnccs-dynamic.la +@MONOLITHIC_TRUE@@USE_LIBTNCCS_TRUE@am__append_75 = $(top_builddir)/src/libtnccs/libtnccs.la +@USE_MEDSRV_TRUE@am__append_76 = plugins/medsrv +@MONOLITHIC_TRUE@@USE_MEDSRV_TRUE@am__append_77 = plugins/medsrv/libstrongswan-medsrv.la +@USE_MEDCLI_TRUE@am__append_78 = plugins/medcli +@MONOLITHIC_TRUE@@USE_MEDCLI_TRUE@am__append_79 = plugins/medcli/libstrongswan-medcli.la +@USE_DHCP_TRUE@am__append_80 = plugins/dhcp +@MONOLITHIC_TRUE@@USE_DHCP_TRUE@am__append_81 = plugins/dhcp/libstrongswan-dhcp.la +@USE_ANDROID_TRUE@am__append_82 = plugins/android +@MONOLITHIC_TRUE@@USE_ANDROID_TRUE@am__append_83 = plugins/android/libstrongswan-android.la +@USE_ANDROID_LOG_TRUE@am__append_84 = plugins/android_log +@MONOLITHIC_TRUE@@USE_ANDROID_LOG_TRUE@am__append_85 = plugins/android_log/libstrongswan-android-log.la +@USE_MAEMO_TRUE@am__append_86 = plugins/maemo +@MONOLITHIC_TRUE@@USE_MAEMO_TRUE@am__append_87 = plugins/maemo/libstrongswan-maemo.la +@USE_HA_TRUE@am__append_88 = plugins/ha +@MONOLITHIC_TRUE@@USE_HA_TRUE@am__append_89 = plugins/ha/libstrongswan-ha.la +@USE_WHITELIST_TRUE@am__append_90 = plugins/whitelist +@MONOLITHIC_TRUE@@USE_WHITELIST_TRUE@am__append_91 = plugins/whitelist/libstrongswan-whitelist.la +@USE_CERTEXPIRE_TRUE@am__append_92 = plugins/certexpire +@MONOLITHIC_TRUE@@USE_CERTEXPIRE_TRUE@am__append_93 = plugins/certexpire/libstrongswan-certexpire.la +@USE_LED_TRUE@am__append_94 = plugins/led +@MONOLITHIC_TRUE@@USE_LED_TRUE@am__append_95 = plugins/led/libstrongswan-led.la +@USE_DUPLICHECK_TRUE@am__append_96 = plugins/duplicheck +@MONOLITHIC_TRUE@@USE_DUPLICHECK_TRUE@am__append_97 = plugins/duplicheck/libstrongswan-duplicheck.la +@USE_COUPLING_TRUE@am__append_98 = plugins/coupling +@MONOLITHIC_TRUE@@USE_COUPLING_TRUE@am__append_99 = plugins/coupling/libstrongswan-coupling.la +@USE_RADATTR_TRUE@am__append_100 = plugins/radattr +@MONOLITHIC_TRUE@@USE_RADATTR_TRUE@am__append_101 = plugins/radattr/libstrongswan-radattr.la +@USE_UCI_TRUE@am__append_102 = plugins/uci +@MONOLITHIC_TRUE@@USE_UCI_TRUE@am__append_103 = plugins/uci/libstrongswan-uci.la +@USE_ADDRBLOCK_TRUE@am__append_104 = plugins/addrblock +@MONOLITHIC_TRUE@@USE_ADDRBLOCK_TRUE@am__append_105 = plugins/addrblock/libstrongswan-addrblock.la +@USE_UNITY_TRUE@am__append_106 = plugins/unity +@MONOLITHIC_TRUE@@USE_UNITY_TRUE@am__append_107 = plugins/unity/libstrongswan-unity.la +@USE_UNIT_TESTS_TRUE@am__append_108 = plugins/unit_tester +@MONOLITHIC_TRUE@@USE_UNIT_TESTS_TRUE@am__append_109 = plugins/unit_tester/libstrongswan-unit-tester.la +@USE_XAUTH_GENERIC_TRUE@am__append_110 = plugins/xauth_generic +@MONOLITHIC_TRUE@@USE_XAUTH_GENERIC_TRUE@am__append_111 = plugins/xauth_generic/libstrongswan-xauth-generic.la +@USE_XAUTH_EAP_TRUE@am__append_112 = plugins/xauth_eap +@MONOLITHIC_TRUE@@USE_XAUTH_EAP_TRUE@am__append_113 = plugins/xauth_eap/libstrongswan-xauth-eap.la +@USE_XAUTH_PAM_TRUE@am__append_114 = plugins/xauth_pam +@MONOLITHIC_TRUE@@USE_XAUTH_PAM_TRUE@am__append_115 = plugins/xauth_pam/libstrongswan-xauth-pam.la subdir = src/libcharon DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -164,6 +217,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -191,37 +245,38 @@ am__installdirs = "$(DESTDIR)$(ipseclibdir)" LTLIBRARIES = $(ipseclib_LTLIBRARIES) am__DEPENDENCIES_1 = libcharon_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__append_4) $(am__append_6) \ - $(am__append_8) $(am__append_10) $(am__append_12) \ - $(am__append_14) $(am__append_16) $(am__append_18) \ - $(am__append_20) $(am__append_22) $(am__append_24) \ - $(am__append_26) $(am__append_28) $(am__append_30) \ - $(am__append_32) $(am__append_34) $(am__append_36) \ - $(am__append_38) $(am__append_39) $(am__append_41) \ - $(am__append_43) $(am__append_45) $(am__append_47) \ - $(am__append_49) $(am__append_51) $(am__append_53) \ - $(am__append_55) $(am__append_56) $(am__append_57) \ - $(am__append_59) $(am__append_61) $(am__append_63) \ - $(am__append_65) $(am__append_67) $(am__append_69) \ - $(am__append_71) $(am__append_73) $(am__append_74) \ - $(am__append_76) $(am__append_78) $(am__append_80) \ - $(am__append_82) $(am__append_84) $(am__append_86) \ - $(am__append_88) $(am__append_90) $(am__append_92) \ - $(am__append_94) $(am__append_96) $(am__append_98) \ - $(am__append_100) $(am__append_102) $(am__append_104) \ - $(am__append_106) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(am__append_5) \ + $(am__append_7) $(am__append_9) $(am__append_11) \ + $(am__append_13) $(am__append_15) $(am__append_17) \ + $(am__append_19) $(am__append_21) $(am__append_23) \ + $(am__append_25) $(am__append_27) $(am__append_29) \ + $(am__append_31) $(am__append_33) $(am__append_35) \ + $(am__append_37) $(am__append_38) $(am__append_40) \ + $(am__append_42) $(am__append_44) $(am__append_46) \ + $(am__append_48) $(am__append_50) $(am__append_52) \ + $(am__append_54) $(am__append_56) $(am__append_57) \ + $(am__append_58) $(am__append_60) $(am__append_62) \ + $(am__append_64) $(am__append_66) $(am__append_68) \ + $(am__append_70) $(am__append_72) $(am__append_74) \ + $(am__append_75) $(am__append_77) $(am__append_79) \ + $(am__append_81) $(am__append_83) $(am__append_85) \ + $(am__append_87) $(am__append_89) $(am__append_91) \ + $(am__append_93) $(am__append_95) $(am__append_97) \ + $(am__append_99) $(am__append_101) $(am__append_103) \ + $(am__append_105) $(am__append_107) $(am__append_109) \ + $(am__append_111) $(am__append_113) $(am__append_115) am__libcharon_la_SOURCES_DIST = bus/bus.c bus/bus.h \ - bus/listeners/listener.h bus/listeners/file_logger.c \ - bus/listeners/file_logger.h bus/listeners/sys_logger.c \ - bus/listeners/sys_logger.h config/backend_manager.c \ - config/backend_manager.h config/backend.h config/child_cfg.c \ - config/child_cfg.h config/ike_cfg.c config/ike_cfg.h \ - config/peer_cfg.c config/peer_cfg.h config/proposal.c \ - config/proposal.h control/controller.c control/controller.h \ - daemon.c daemon.h encoding/generator.c encoding/generator.h \ - encoding/message.c encoding/message.h encoding/parser.c \ - encoding/parser.h encoding/payloads/auth_payload.c \ + bus/listeners/listener.h bus/listeners/logger.h \ + bus/listeners/file_logger.c bus/listeners/file_logger.h \ + bus/listeners/sys_logger.c bus/listeners/sys_logger.h \ + config/backend_manager.c config/backend_manager.h \ + config/backend.h config/child_cfg.c config/child_cfg.h \ + config/ike_cfg.c config/ike_cfg.h config/peer_cfg.c \ + config/peer_cfg.h config/proposal.c config/proposal.h \ + control/controller.c control/controller.h daemon.c daemon.h \ + encoding/generator.c encoding/generator.h encoding/message.c \ + encoding/message.h encoding/parser.c encoding/parser.h \ + encoding/payloads/auth_payload.c \ encoding/payloads/auth_payload.h \ encoding/payloads/cert_payload.c \ encoding/payloads/cert_payload.h \ @@ -258,12 +313,14 @@ am__libcharon_la_SOURCES_DIST = bus/bus.c bus/bus.h \ encoding/payloads/unknown_payload.c \ encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c \ - encoding/payloads/vendor_id_payload.h kernel/kernel_handler.c \ + encoding/payloads/vendor_id_payload.h \ + encoding/payloads/hash_payload.c \ + encoding/payloads/hash_payload.h kernel/kernel_handler.c \ kernel/kernel_handler.h network/receiver.c network/receiver.h \ - network/sender.c network/sender.h network/packet.c \ - network/packet.h network/socket.c network/socket.h \ - network/socket_manager.c network/socket_manager.h \ - processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ + network/sender.c network/sender.h network/socket.c \ + network/socket.h network/socket_manager.c \ + network/socket_manager.h processing/jobs/acquire_job.c \ + processing/jobs/acquire_job.h \ processing/jobs/delete_child_sa_job.c \ processing/jobs/delete_child_sa_job.h \ processing/jobs/delete_ike_sa_job.c \ @@ -277,6 +334,8 @@ am__libcharon_la_SOURCES_DIST = bus/bus.c bus/bus.h \ processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c \ processing/jobs/retransmit_job.h \ + processing/jobs/retry_initiate_job.c \ + processing/jobs/retry_initiate_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c \ processing/jobs/send_keepalive_job.h \ @@ -285,47 +344,97 @@ am__libcharon_la_SOURCES_DIST = bus/bus.c bus/bus.h \ processing/jobs/roam_job.h processing/jobs/update_sa_job.c \ processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c \ - processing/jobs/inactivity_job.h \ - sa/authenticators/authenticator.c \ - sa/authenticators/authenticator.h \ - sa/authenticators/eap_authenticator.c \ - sa/authenticators/eap_authenticator.h \ - sa/authenticators/eap/eap_method.c \ - sa/authenticators/eap/eap_method.h \ - sa/authenticators/eap/eap_manager.c \ - sa/authenticators/eap/eap_manager.h \ - sa/authenticators/psk_authenticator.c \ - sa/authenticators/psk_authenticator.h \ - sa/authenticators/pubkey_authenticator.c \ - sa/authenticators/pubkey_authenticator.h sa/child_sa.c \ + processing/jobs/inactivity_job.h sa/eap/eap_method.c \ + sa/eap/eap_method.h sa/eap/eap_manager.c sa/eap/eap_manager.h \ + sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ + sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ + sa/authenticator.c sa/authenticator.h sa/child_sa.c \ sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_id.c \ - sa/ike_sa_id.h sa/ike_sa_manager.c sa/ike_sa_manager.h \ - sa/task_manager.c sa/task_manager.h sa/keymat.c sa/keymat.h \ + sa/ike_sa_id.h sa/keymat.h sa/keymat.c sa/ike_sa_manager.c \ + sa/ike_sa_manager.h sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h sa/trap_manager.c \ - sa/trap_manager.h sa/tasks/child_create.c \ - sa/tasks/child_create.h sa/tasks/child_delete.c \ - sa/tasks/child_delete.h sa/tasks/child_rekey.c \ - sa/tasks/child_rekey.h sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ - sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ - sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ - sa/tasks/ike_config.c sa/tasks/ike_config.h \ - sa/tasks/ike_delete.c sa/tasks/ike_delete.h sa/tasks/ike_dpd.c \ - sa/tasks/ike_dpd.h sa/tasks/ike_init.c sa/tasks/ike_init.h \ - sa/tasks/ike_natd.c sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \ - sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \ - sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \ - sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \ - sa/tasks/ike_auth_lifetime.h sa/tasks/ike_vendor.c \ - sa/tasks/ike_vendor.h sa/tasks/task.c sa/tasks/task.h \ + sa/trap_manager.h sa/task.c sa/task.h sa/ikev2/keymat_v2.c \ + sa/ikev2/keymat_v2.h sa/ikev2/task_manager_v2.c \ + sa/ikev2/task_manager_v2.h \ + sa/ikev2/authenticators/eap_authenticator.c \ + sa/ikev2/authenticators/eap_authenticator.h \ + sa/ikev2/authenticators/psk_authenticator.c \ + sa/ikev2/authenticators/psk_authenticator.h \ + sa/ikev2/authenticators/pubkey_authenticator.c \ + sa/ikev2/authenticators/pubkey_authenticator.h \ + sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ + sa/ikev2/tasks/child_delete.c sa/ikev2/tasks/child_delete.h \ + sa/ikev2/tasks/child_rekey.c sa/ikev2/tasks/child_rekey.h \ + sa/ikev2/tasks/ike_auth.c sa/ikev2/tasks/ike_auth.h \ + sa/ikev2/tasks/ike_cert_pre.c sa/ikev2/tasks/ike_cert_pre.h \ + sa/ikev2/tasks/ike_cert_post.c sa/ikev2/tasks/ike_cert_post.h \ + sa/ikev2/tasks/ike_config.c sa/ikev2/tasks/ike_config.h \ + sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \ + sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \ + sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \ + sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \ + sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ + sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ + sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ + sa/ikev2/tasks/ike_auth_lifetime.c \ + sa/ikev2/tasks/ike_auth_lifetime.h sa/ikev2/tasks/ike_vendor.c \ + sa/ikev2/tasks/ike_vendor.h sa/ikev1/keymat_v1.c \ + sa/ikev1/keymat_v1.h sa/ikev1/task_manager_v1.c \ + sa/ikev1/task_manager_v1.h \ + sa/ikev1/authenticators/psk_v1_authenticator.c \ + sa/ikev1/authenticators/psk_v1_authenticator.h \ + sa/ikev1/authenticators/pubkey_v1_authenticator.c \ + sa/ikev1/authenticators/pubkey_v1_authenticator.h \ + sa/ikev1/authenticators/hybrid_authenticator.c \ + sa/ikev1/authenticators/hybrid_authenticator.h \ + sa/ikev1/phase1.c sa/ikev1/phase1.h sa/ikev1/tasks/main_mode.c \ + sa/ikev1/tasks/main_mode.h sa/ikev1/tasks/aggressive_mode.c \ + sa/ikev1/tasks/aggressive_mode.h \ + sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ + sa/ikev1/tasks/isakmp_cert_pre.c \ + sa/ikev1/tasks/isakmp_cert_pre.h \ + sa/ikev1/tasks/isakmp_cert_post.c \ + sa/ikev1/tasks/isakmp_cert_post.h sa/ikev1/tasks/isakmp_natd.c \ + sa/ikev1/tasks/isakmp_natd.h sa/ikev1/tasks/isakmp_vendor.c \ + sa/ikev1/tasks/isakmp_vendor.h sa/ikev1/tasks/isakmp_delete.c \ + sa/ikev1/tasks/isakmp_delete.h sa/ikev1/tasks/isakmp_dpd.c \ + sa/ikev1/tasks/isakmp_dpd.h sa/ikev1/tasks/xauth.c \ + sa/ikev1/tasks/xauth.h sa/ikev1/tasks/quick_mode.c \ + sa/ikev1/tasks/quick_mode.h sa/ikev1/tasks/quick_delete.c \ + sa/ikev1/tasks/quick_delete.h sa/ikev1/tasks/mode_config.c \ + sa/ikev1/tasks/mode_config.h processing/jobs/dpd_timeout_job.c \ + processing/jobs/dpd_timeout_job.h \ + processing/jobs/adopt_children_job.c \ + processing/jobs/adopt_children_job.h \ encoding/payloads/endpoint_notify.c \ encoding/payloads/endpoint_notify.h \ processing/jobs/initiate_mediation_job.c \ processing/jobs/initiate_mediation_job.h \ processing/jobs/mediation_job.c \ - processing/jobs/mediation_job.h sa/connect_manager.c \ - sa/connect_manager.h sa/mediation_manager.c \ - sa/mediation_manager.h sa/tasks/ike_me.c sa/tasks/ike_me.h -@USE_ME_TRUE@am__objects_1 = endpoint_notify.lo \ + processing/jobs/mediation_job.h sa/ikev2/connect_manager.c \ + sa/ikev2/connect_manager.h sa/ikev2/mediation_manager.c \ + sa/ikev2/mediation_manager.h sa/ikev2/tasks/ike_me.c \ + sa/ikev2/tasks/ike_me.h +@USE_IKEV2_TRUE@am__objects_1 = keymat_v2.lo task_manager_v2.lo \ +@USE_IKEV2_TRUE@ eap_authenticator.lo psk_authenticator.lo \ +@USE_IKEV2_TRUE@ pubkey_authenticator.lo child_create.lo \ +@USE_IKEV2_TRUE@ child_delete.lo child_rekey.lo ike_auth.lo \ +@USE_IKEV2_TRUE@ ike_cert_pre.lo ike_cert_post.lo ike_config.lo \ +@USE_IKEV2_TRUE@ ike_delete.lo ike_dpd.lo ike_init.lo \ +@USE_IKEV2_TRUE@ ike_natd.lo ike_mobike.lo ike_rekey.lo \ +@USE_IKEV2_TRUE@ ike_reauth.lo ike_auth_lifetime.lo \ +@USE_IKEV2_TRUE@ ike_vendor.lo +@USE_IKEV1_TRUE@am__objects_2 = keymat_v1.lo task_manager_v1.lo \ +@USE_IKEV1_TRUE@ psk_v1_authenticator.lo \ +@USE_IKEV1_TRUE@ pubkey_v1_authenticator.lo \ +@USE_IKEV1_TRUE@ hybrid_authenticator.lo phase1.lo main_mode.lo \ +@USE_IKEV1_TRUE@ aggressive_mode.lo informational.lo \ +@USE_IKEV1_TRUE@ isakmp_cert_pre.lo isakmp_cert_post.lo \ +@USE_IKEV1_TRUE@ isakmp_natd.lo isakmp_vendor.lo \ +@USE_IKEV1_TRUE@ isakmp_delete.lo isakmp_dpd.lo xauth.lo \ +@USE_IKEV1_TRUE@ quick_mode.lo quick_delete.lo mode_config.lo \ +@USE_IKEV1_TRUE@ dpd_timeout_job.lo adopt_children_job.lo +@USE_ME_TRUE@am__objects_3 = endpoint_notify.lo \ @USE_ME_TRUE@ initiate_mediation_job.lo mediation_job.lo \ @USE_ME_TRUE@ connect_manager.lo mediation_manager.lo ike_me.lo am_libcharon_la_OBJECTS = bus.lo file_logger.lo sys_logger.lo \ @@ -338,24 +447,20 @@ am_libcharon_la_OBJECTS = bus.lo file_logger.lo sys_logger.lo \ notify_payload.lo payload.lo proposal_substructure.lo \ sa_payload.lo traffic_selector_substructure.lo \ transform_attribute.lo transform_substructure.lo ts_payload.lo \ - unknown_payload.lo vendor_id_payload.lo kernel_handler.lo \ - receiver.lo sender.lo packet.lo socket.lo socket_manager.lo \ - acquire_job.lo delete_child_sa_job.lo delete_ike_sa_job.lo \ - migrate_job.lo process_message_job.lo rekey_child_sa_job.lo \ - rekey_ike_sa_job.lo retransmit_job.lo send_dpd_job.lo \ - send_keepalive_job.lo start_action_job.lo roam_job.lo \ - update_sa_job.lo inactivity_job.lo authenticator.lo \ - eap_authenticator.lo eap_method.lo eap_manager.lo \ - psk_authenticator.lo pubkey_authenticator.lo child_sa.lo \ - ike_sa.lo ike_sa_id.lo ike_sa_manager.lo task_manager.lo \ - keymat.lo shunt_manager.lo trap_manager.lo child_create.lo \ - child_delete.lo child_rekey.lo ike_auth.lo ike_cert_pre.lo \ - ike_cert_post.lo ike_config.lo ike_delete.lo ike_dpd.lo \ - ike_init.lo ike_natd.lo ike_mobike.lo ike_rekey.lo \ - ike_reauth.lo ike_auth_lifetime.lo ike_vendor.lo task.lo \ - $(am__objects_1) + unknown_payload.lo vendor_id_payload.lo hash_payload.lo \ + kernel_handler.lo receiver.lo sender.lo socket.lo \ + socket_manager.lo acquire_job.lo delete_child_sa_job.lo \ + delete_ike_sa_job.lo migrate_job.lo process_message_job.lo \ + rekey_child_sa_job.lo rekey_ike_sa_job.lo retransmit_job.lo \ + retry_initiate_job.lo send_dpd_job.lo send_keepalive_job.lo \ + start_action_job.lo roam_job.lo update_sa_job.lo \ + inactivity_job.lo eap_method.lo eap_manager.lo xauth_method.lo \ + xauth_manager.lo authenticator.lo child_sa.lo ike_sa.lo \ + ike_sa_id.lo keymat.lo ike_sa_manager.lo task_manager.lo \ + shunt_manager.lo trap_manager.lo task.lo $(am__objects_1) \ + $(am__objects_2) $(am__objects_3) libcharon_la_OBJECTS = $(am_libcharon_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -385,22 +490,23 @@ AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ ETAGS = etags CTAGS = ctags DIST_SUBDIRS = . plugins/load_tester plugins/socket_default \ - plugins/socket_raw plugins/socket_dynamic plugins/farp \ - plugins/stroke plugins/smp plugins/sql plugins/updown \ - plugins/eap_identity plugins/eap_sim plugins/eap_sim_file \ - plugins/eap_sim_pcsc plugins/eap_simaka_sql \ - plugins/eap_simaka_pseudonym plugins/eap_simaka_reauth \ - plugins/eap_aka plugins/eap_aka_3gpp2 plugins/eap_md5 \ - plugins/eap_gtc plugins/eap_mschapv2 plugins/eap_radius \ + plugins/socket_dynamic plugins/farp plugins/stroke plugins/smp \ + plugins/sql plugins/updown plugins/eap_identity \ + plugins/eap_sim plugins/eap_sim_file plugins/eap_sim_pcsc \ + plugins/eap_simaka_sql plugins/eap_simaka_pseudonym \ + plugins/eap_simaka_reauth plugins/eap_aka \ + plugins/eap_aka_3gpp2 plugins/eap_md5 plugins/eap_gtc \ + plugins/eap_mschapv2 plugins/eap_dynamic plugins/eap_radius \ plugins/eap_tls plugins/eap_ttls plugins/eap_peap \ plugins/eap_tnc plugins/tnc_ifmap plugins/tnc_pdp \ plugins/tnc_imc plugins/tnc_imv plugins/tnc_tnccs \ plugins/tnccs_11 plugins/tnccs_20 plugins/tnccs_dynamic \ - plugins/medsrv plugins/medcli plugins/nm plugins/dhcp \ - plugins/android plugins/maemo plugins/ha plugins/whitelist \ + plugins/medsrv plugins/medcli plugins/dhcp plugins/android \ + plugins/android_log plugins/maemo plugins/ha plugins/whitelist \ plugins/certexpire plugins/led plugins/duplicheck \ plugins/coupling plugins/radattr plugins/uci plugins/addrblock \ - plugins/unit_tester + plugins/unity plugins/unit_tester plugins/xauth_generic \ + plugins/xauth_eap plugins/xauth_pam DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ @@ -435,6 +541,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -529,11 +636,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -550,11 +660,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -570,6 +681,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -579,7 +691,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -609,16 +720,16 @@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ ipseclib_LTLIBRARIES = libcharon.la libcharon_la_SOURCES = bus/bus.c bus/bus.h bus/listeners/listener.h \ - bus/listeners/file_logger.c bus/listeners/file_logger.h \ - bus/listeners/sys_logger.c bus/listeners/sys_logger.h \ - config/backend_manager.c config/backend_manager.h \ - config/backend.h config/child_cfg.c config/child_cfg.h \ - config/ike_cfg.c config/ike_cfg.h config/peer_cfg.c \ - config/peer_cfg.h config/proposal.c config/proposal.h \ - control/controller.c control/controller.h daemon.c daemon.h \ - encoding/generator.c encoding/generator.h encoding/message.c \ - encoding/message.h encoding/parser.c encoding/parser.h \ - encoding/payloads/auth_payload.c \ + bus/listeners/logger.h bus/listeners/file_logger.c \ + bus/listeners/file_logger.h bus/listeners/sys_logger.c \ + bus/listeners/sys_logger.h config/backend_manager.c \ + config/backend_manager.h config/backend.h config/child_cfg.c \ + config/child_cfg.h config/ike_cfg.c config/ike_cfg.h \ + config/peer_cfg.c config/peer_cfg.h config/proposal.c \ + config/proposal.h control/controller.c control/controller.h \ + daemon.c daemon.h encoding/generator.c encoding/generator.h \ + encoding/message.c encoding/message.h encoding/parser.c \ + encoding/parser.h encoding/payloads/auth_payload.c \ encoding/payloads/auth_payload.h \ encoding/payloads/cert_payload.c \ encoding/payloads/cert_payload.h \ @@ -655,12 +766,14 @@ libcharon_la_SOURCES = bus/bus.c bus/bus.h bus/listeners/listener.h \ encoding/payloads/unknown_payload.c \ encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c \ - encoding/payloads/vendor_id_payload.h kernel/kernel_handler.c \ + encoding/payloads/vendor_id_payload.h \ + encoding/payloads/hash_payload.c \ + encoding/payloads/hash_payload.h kernel/kernel_handler.c \ kernel/kernel_handler.h network/receiver.c network/receiver.h \ - network/sender.c network/sender.h network/packet.c \ - network/packet.h network/socket.c network/socket.h \ - network/socket_manager.c network/socket_manager.h \ - processing/jobs/acquire_job.c processing/jobs/acquire_job.h \ + network/sender.c network/sender.h network/socket.c \ + network/socket.h network/socket_manager.c \ + network/socket_manager.h processing/jobs/acquire_job.c \ + processing/jobs/acquire_job.h \ processing/jobs/delete_child_sa_job.c \ processing/jobs/delete_child_sa_job.h \ processing/jobs/delete_ike_sa_job.c \ @@ -674,6 +787,8 @@ libcharon_la_SOURCES = bus/bus.c bus/bus.h bus/listeners/listener.h \ processing/jobs/rekey_ike_sa_job.h \ processing/jobs/retransmit_job.c \ processing/jobs/retransmit_job.h \ + processing/jobs/retry_initiate_job.c \ + processing/jobs/retry_initiate_job.h \ processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \ processing/jobs/send_keepalive_job.c \ processing/jobs/send_keepalive_job.h \ @@ -682,39 +797,17 @@ libcharon_la_SOURCES = bus/bus.c bus/bus.h bus/listeners/listener.h \ processing/jobs/roam_job.h processing/jobs/update_sa_job.c \ processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c \ - processing/jobs/inactivity_job.h \ - sa/authenticators/authenticator.c \ - sa/authenticators/authenticator.h \ - sa/authenticators/eap_authenticator.c \ - sa/authenticators/eap_authenticator.h \ - sa/authenticators/eap/eap_method.c \ - sa/authenticators/eap/eap_method.h \ - sa/authenticators/eap/eap_manager.c \ - sa/authenticators/eap/eap_manager.h \ - sa/authenticators/psk_authenticator.c \ - sa/authenticators/psk_authenticator.h \ - sa/authenticators/pubkey_authenticator.c \ - sa/authenticators/pubkey_authenticator.h sa/child_sa.c \ + processing/jobs/inactivity_job.h sa/eap/eap_method.c \ + sa/eap/eap_method.h sa/eap/eap_manager.c sa/eap/eap_manager.h \ + sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ + sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ + sa/authenticator.c sa/authenticator.h sa/child_sa.c \ sa/child_sa.h sa/ike_sa.c sa/ike_sa.h sa/ike_sa_id.c \ - sa/ike_sa_id.h sa/ike_sa_manager.c sa/ike_sa_manager.h \ - sa/task_manager.c sa/task_manager.h sa/keymat.c sa/keymat.h \ + sa/ike_sa_id.h sa/keymat.h sa/keymat.c sa/ike_sa_manager.c \ + sa/ike_sa_manager.h sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h sa/trap_manager.c \ - sa/trap_manager.h sa/tasks/child_create.c \ - sa/tasks/child_create.h sa/tasks/child_delete.c \ - sa/tasks/child_delete.h sa/tasks/child_rekey.c \ - sa/tasks/child_rekey.h sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ - sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ - sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ - sa/tasks/ike_config.c sa/tasks/ike_config.h \ - sa/tasks/ike_delete.c sa/tasks/ike_delete.h sa/tasks/ike_dpd.c \ - sa/tasks/ike_dpd.h sa/tasks/ike_init.c sa/tasks/ike_init.h \ - sa/tasks/ike_natd.c sa/tasks/ike_natd.h sa/tasks/ike_mobike.c \ - sa/tasks/ike_mobike.h sa/tasks/ike_rekey.c \ - sa/tasks/ike_rekey.h sa/tasks/ike_reauth.c \ - sa/tasks/ike_reauth.h sa/tasks/ike_auth_lifetime.c \ - sa/tasks/ike_auth_lifetime.h sa/tasks/ike_vendor.c \ - sa/tasks/ike_vendor.h sa/tasks/task.c sa/tasks/task.h \ - $(am__append_1) + sa/trap_manager.h sa/task.c sa/task.h $(am__append_1) \ + $(am__append_2) $(am__append_3) INCLUDES = \ -I${linux_headers} \ -I$(top_srcdir)/src/libstrongswan \ @@ -723,83 +816,87 @@ INCLUDES = \ AM_CFLAGS = \ -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_PIDDIR=\"${piddir}\" \ - -DPLUGINS=\""${libcharon_plugins}\"" + -DIPSEC_PIDDIR=\"${piddir}\" libcharon_la_LIBADD = -lm $(PTHREADLIB) $(DLLIB) $(SOCKLIB) \ - $(am__append_2) $(am__append_4) $(am__append_6) \ - $(am__append_8) $(am__append_10) $(am__append_12) \ - $(am__append_14) $(am__append_16) $(am__append_18) \ - $(am__append_20) $(am__append_22) $(am__append_24) \ - $(am__append_26) $(am__append_28) $(am__append_30) \ - $(am__append_32) $(am__append_34) $(am__append_36) \ - $(am__append_38) $(am__append_39) $(am__append_41) \ - $(am__append_43) $(am__append_45) $(am__append_47) \ - $(am__append_49) $(am__append_51) $(am__append_53) \ - $(am__append_55) $(am__append_56) $(am__append_57) \ - $(am__append_59) $(am__append_61) $(am__append_63) \ - $(am__append_65) $(am__append_67) $(am__append_69) \ - $(am__append_71) $(am__append_73) $(am__append_74) \ - $(am__append_76) $(am__append_78) $(am__append_80) \ - $(am__append_82) $(am__append_84) $(am__append_86) \ - $(am__append_88) $(am__append_90) $(am__append_92) \ - $(am__append_94) $(am__append_96) $(am__append_98) \ - $(am__append_100) $(am__append_102) $(am__append_104) \ - $(am__append_106) + $(am__append_5) $(am__append_7) $(am__append_9) \ + $(am__append_11) $(am__append_13) $(am__append_15) \ + $(am__append_17) $(am__append_19) $(am__append_21) \ + $(am__append_23) $(am__append_25) $(am__append_27) \ + $(am__append_29) $(am__append_31) $(am__append_33) \ + $(am__append_35) $(am__append_37) $(am__append_38) \ + $(am__append_40) $(am__append_42) $(am__append_44) \ + $(am__append_46) $(am__append_48) $(am__append_50) \ + $(am__append_52) $(am__append_54) $(am__append_56) \ + $(am__append_57) $(am__append_58) $(am__append_60) \ + $(am__append_62) $(am__append_64) $(am__append_66) \ + $(am__append_68) $(am__append_70) $(am__append_72) \ + $(am__append_74) $(am__append_75) $(am__append_77) \ + $(am__append_79) $(am__append_81) $(am__append_83) \ + $(am__append_85) $(am__append_87) $(am__append_89) \ + $(am__append_91) $(am__append_93) $(am__append_95) \ + $(am__append_97) $(am__append_99) $(am__append_101) \ + $(am__append_103) $(am__append_105) $(am__append_107) \ + $(am__append_109) $(am__append_111) $(am__append_113) \ + $(am__append_115) EXTRA_DIST = Android.mk -@MONOLITHIC_FALSE@SUBDIRS = . $(am__append_3) $(am__append_5) \ -@MONOLITHIC_FALSE@ $(am__append_7) $(am__append_9) \ -@MONOLITHIC_FALSE@ $(am__append_11) $(am__append_13) \ -@MONOLITHIC_FALSE@ $(am__append_15) $(am__append_17) \ -@MONOLITHIC_FALSE@ $(am__append_19) $(am__append_21) \ -@MONOLITHIC_FALSE@ $(am__append_23) $(am__append_25) \ -@MONOLITHIC_FALSE@ $(am__append_27) $(am__append_29) \ -@MONOLITHIC_FALSE@ $(am__append_31) $(am__append_33) \ -@MONOLITHIC_FALSE@ $(am__append_35) $(am__append_37) \ -@MONOLITHIC_FALSE@ $(am__append_40) $(am__append_42) \ -@MONOLITHIC_FALSE@ $(am__append_44) $(am__append_46) \ -@MONOLITHIC_FALSE@ $(am__append_48) $(am__append_50) \ -@MONOLITHIC_FALSE@ $(am__append_52) $(am__append_54) \ -@MONOLITHIC_FALSE@ $(am__append_58) $(am__append_60) \ -@MONOLITHIC_FALSE@ $(am__append_62) $(am__append_64) \ -@MONOLITHIC_FALSE@ $(am__append_66) $(am__append_68) \ -@MONOLITHIC_FALSE@ $(am__append_70) $(am__append_72) \ -@MONOLITHIC_FALSE@ $(am__append_75) $(am__append_77) \ -@MONOLITHIC_FALSE@ $(am__append_79) $(am__append_81) \ -@MONOLITHIC_FALSE@ $(am__append_83) $(am__append_85) \ -@MONOLITHIC_FALSE@ $(am__append_87) $(am__append_89) \ -@MONOLITHIC_FALSE@ $(am__append_91) $(am__append_93) \ -@MONOLITHIC_FALSE@ $(am__append_95) $(am__append_97) \ -@MONOLITHIC_FALSE@ $(am__append_99) $(am__append_101) \ -@MONOLITHIC_FALSE@ $(am__append_103) $(am__append_105) +@MONOLITHIC_FALSE@SUBDIRS = . $(am__append_4) $(am__append_6) \ +@MONOLITHIC_FALSE@ $(am__append_8) $(am__append_10) \ +@MONOLITHIC_FALSE@ $(am__append_12) $(am__append_14) \ +@MONOLITHIC_FALSE@ $(am__append_16) $(am__append_18) \ +@MONOLITHIC_FALSE@ $(am__append_20) $(am__append_22) \ +@MONOLITHIC_FALSE@ $(am__append_24) $(am__append_26) \ +@MONOLITHIC_FALSE@ $(am__append_28) $(am__append_30) \ +@MONOLITHIC_FALSE@ $(am__append_32) $(am__append_34) \ +@MONOLITHIC_FALSE@ $(am__append_36) $(am__append_39) \ +@MONOLITHIC_FALSE@ $(am__append_41) $(am__append_43) \ +@MONOLITHIC_FALSE@ $(am__append_45) $(am__append_47) \ +@MONOLITHIC_FALSE@ $(am__append_49) $(am__append_51) \ +@MONOLITHIC_FALSE@ $(am__append_53) $(am__append_55) \ +@MONOLITHIC_FALSE@ $(am__append_59) $(am__append_61) \ +@MONOLITHIC_FALSE@ $(am__append_63) $(am__append_65) \ +@MONOLITHIC_FALSE@ $(am__append_67) $(am__append_69) \ +@MONOLITHIC_FALSE@ $(am__append_71) $(am__append_73) \ +@MONOLITHIC_FALSE@ $(am__append_76) $(am__append_78) \ +@MONOLITHIC_FALSE@ $(am__append_80) $(am__append_82) \ +@MONOLITHIC_FALSE@ $(am__append_84) $(am__append_86) \ +@MONOLITHIC_FALSE@ $(am__append_88) $(am__append_90) \ +@MONOLITHIC_FALSE@ $(am__append_92) $(am__append_94) \ +@MONOLITHIC_FALSE@ $(am__append_96) $(am__append_98) \ +@MONOLITHIC_FALSE@ $(am__append_100) $(am__append_102) \ +@MONOLITHIC_FALSE@ $(am__append_104) $(am__append_106) \ +@MONOLITHIC_FALSE@ $(am__append_108) $(am__append_110) \ +@MONOLITHIC_FALSE@ $(am__append_112) $(am__append_114) # build optional plugins ######################## -@MONOLITHIC_TRUE@SUBDIRS = $(am__append_3) $(am__append_5) \ -@MONOLITHIC_TRUE@ $(am__append_7) $(am__append_9) \ -@MONOLITHIC_TRUE@ $(am__append_11) $(am__append_13) \ -@MONOLITHIC_TRUE@ $(am__append_15) $(am__append_17) \ -@MONOLITHIC_TRUE@ $(am__append_19) $(am__append_21) \ -@MONOLITHIC_TRUE@ $(am__append_23) $(am__append_25) \ -@MONOLITHIC_TRUE@ $(am__append_27) $(am__append_29) \ -@MONOLITHIC_TRUE@ $(am__append_31) $(am__append_33) \ -@MONOLITHIC_TRUE@ $(am__append_35) $(am__append_37) \ -@MONOLITHIC_TRUE@ $(am__append_40) $(am__append_42) \ -@MONOLITHIC_TRUE@ $(am__append_44) $(am__append_46) \ -@MONOLITHIC_TRUE@ $(am__append_48) $(am__append_50) \ -@MONOLITHIC_TRUE@ $(am__append_52) $(am__append_54) \ -@MONOLITHIC_TRUE@ $(am__append_58) $(am__append_60) \ -@MONOLITHIC_TRUE@ $(am__append_62) $(am__append_64) \ -@MONOLITHIC_TRUE@ $(am__append_66) $(am__append_68) \ -@MONOLITHIC_TRUE@ $(am__append_70) $(am__append_72) \ -@MONOLITHIC_TRUE@ $(am__append_75) $(am__append_77) \ -@MONOLITHIC_TRUE@ $(am__append_79) $(am__append_81) \ -@MONOLITHIC_TRUE@ $(am__append_83) $(am__append_85) \ -@MONOLITHIC_TRUE@ $(am__append_87) $(am__append_89) \ -@MONOLITHIC_TRUE@ $(am__append_91) $(am__append_93) \ -@MONOLITHIC_TRUE@ $(am__append_95) $(am__append_97) \ -@MONOLITHIC_TRUE@ $(am__append_99) $(am__append_101) \ -@MONOLITHIC_TRUE@ $(am__append_103) $(am__append_105) +@MONOLITHIC_TRUE@SUBDIRS = $(am__append_4) $(am__append_6) \ +@MONOLITHIC_TRUE@ $(am__append_8) $(am__append_10) \ +@MONOLITHIC_TRUE@ $(am__append_12) $(am__append_14) \ +@MONOLITHIC_TRUE@ $(am__append_16) $(am__append_18) \ +@MONOLITHIC_TRUE@ $(am__append_20) $(am__append_22) \ +@MONOLITHIC_TRUE@ $(am__append_24) $(am__append_26) \ +@MONOLITHIC_TRUE@ $(am__append_28) $(am__append_30) \ +@MONOLITHIC_TRUE@ $(am__append_32) $(am__append_34) \ +@MONOLITHIC_TRUE@ $(am__append_36) $(am__append_39) \ +@MONOLITHIC_TRUE@ $(am__append_41) $(am__append_43) \ +@MONOLITHIC_TRUE@ $(am__append_45) $(am__append_47) \ +@MONOLITHIC_TRUE@ $(am__append_49) $(am__append_51) \ +@MONOLITHIC_TRUE@ $(am__append_53) $(am__append_55) \ +@MONOLITHIC_TRUE@ $(am__append_59) $(am__append_61) \ +@MONOLITHIC_TRUE@ $(am__append_63) $(am__append_65) \ +@MONOLITHIC_TRUE@ $(am__append_67) $(am__append_69) \ +@MONOLITHIC_TRUE@ $(am__append_71) $(am__append_73) \ +@MONOLITHIC_TRUE@ $(am__append_76) $(am__append_78) \ +@MONOLITHIC_TRUE@ $(am__append_80) $(am__append_82) \ +@MONOLITHIC_TRUE@ $(am__append_84) $(am__append_86) \ +@MONOLITHIC_TRUE@ $(am__append_88) $(am__append_90) \ +@MONOLITHIC_TRUE@ $(am__append_92) $(am__append_94) \ +@MONOLITHIC_TRUE@ $(am__append_96) $(am__append_98) \ +@MONOLITHIC_TRUE@ $(am__append_100) $(am__append_102) \ +@MONOLITHIC_TRUE@ $(am__append_104) $(am__append_106) \ +@MONOLITHIC_TRUE@ $(am__append_108) $(am__append_110) \ +@MONOLITHIC_TRUE@ $(am__append_112) $(am__append_114) all: all-recursive .SUFFIXES: @@ -875,6 +972,8 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/acquire_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adopt_children_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aggressive_mode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/authenticator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_manager.Plo@am__quote@ @@ -894,6 +993,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_child_sa_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_ike_sa_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/delete_payload.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dpd_timeout_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_authenticator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_method.Plo@am__quote@ @@ -903,6 +1003,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/endpoint_notify.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_payload.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hybrid_authenticator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_auth_lifetime.Plo@am__quote@ @@ -924,29 +1026,45 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_vendor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inactivity_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/informational.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initiate_mediation_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_cert_post.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_cert_pre.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_delete.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_dpd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_natd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/isakmp_vendor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ke_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keymat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keymat_v1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keymat_v2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main_mode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mediation_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mediation_manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/migrate_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mode_config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonce_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify_payload.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer_cfg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/phase1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process_message_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_substructure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_authenticator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_v1_authenticator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubkey_authenticator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pubkey_v1_authenticator.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quick_delete.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quick_mode.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/receiver.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_child_sa_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_ike_sa_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retransmit_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retry_initiate_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/roam_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sa_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/send_dpd_job.Plo@am__quote@ @@ -959,6 +1077,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager_v1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager_v2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector_substructure.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_attribute.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_substructure.Plo@am__quote@ @@ -967,6 +1087,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unknown_payload.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/update_sa_job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendor_id_payload.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_method.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -1234,6 +1357,13 @@ vendor_id_payload.lo: encoding/payloads/vendor_id_payload.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o vendor_id_payload.lo `test -f 'encoding/payloads/vendor_id_payload.c' || echo '$(srcdir)/'`encoding/payloads/vendor_id_payload.c +hash_payload.lo: encoding/payloads/hash_payload.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hash_payload.lo -MD -MP -MF $(DEPDIR)/hash_payload.Tpo -c -o hash_payload.lo `test -f 'encoding/payloads/hash_payload.c' || echo '$(srcdir)/'`encoding/payloads/hash_payload.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hash_payload.Tpo $(DEPDIR)/hash_payload.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='encoding/payloads/hash_payload.c' object='hash_payload.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hash_payload.lo `test -f 'encoding/payloads/hash_payload.c' || echo '$(srcdir)/'`encoding/payloads/hash_payload.c + kernel_handler.lo: kernel/kernel_handler.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT kernel_handler.lo -MD -MP -MF $(DEPDIR)/kernel_handler.Tpo -c -o kernel_handler.lo `test -f 'kernel/kernel_handler.c' || echo '$(srcdir)/'`kernel/kernel_handler.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/kernel_handler.Tpo $(DEPDIR)/kernel_handler.Plo @@ -1255,13 +1385,6 @@ sender.lo: network/sender.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sender.lo `test -f 'network/sender.c' || echo '$(srcdir)/'`network/sender.c -packet.lo: network/packet.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.lo -MD -MP -MF $(DEPDIR)/packet.Tpo -c -o packet.lo `test -f 'network/packet.c' || echo '$(srcdir)/'`network/packet.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet.Tpo $(DEPDIR)/packet.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='network/packet.c' object='packet.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.lo `test -f 'network/packet.c' || echo '$(srcdir)/'`network/packet.c - socket.lo: network/socket.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT socket.lo -MD -MP -MF $(DEPDIR)/socket.Tpo -c -o socket.lo `test -f 'network/socket.c' || echo '$(srcdir)/'`network/socket.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/socket.Tpo $(DEPDIR)/socket.Plo @@ -1332,6 +1455,13 @@ retransmit_job.lo: processing/jobs/retransmit_job.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o retransmit_job.lo `test -f 'processing/jobs/retransmit_job.c' || echo '$(srcdir)/'`processing/jobs/retransmit_job.c +retry_initiate_job.lo: processing/jobs/retry_initiate_job.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT retry_initiate_job.lo -MD -MP -MF $(DEPDIR)/retry_initiate_job.Tpo -c -o retry_initiate_job.lo `test -f 'processing/jobs/retry_initiate_job.c' || echo '$(srcdir)/'`processing/jobs/retry_initiate_job.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/retry_initiate_job.Tpo $(DEPDIR)/retry_initiate_job.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/retry_initiate_job.c' object='retry_initiate_job.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o retry_initiate_job.lo `test -f 'processing/jobs/retry_initiate_job.c' || echo '$(srcdir)/'`processing/jobs/retry_initiate_job.c + send_dpd_job.lo: processing/jobs/send_dpd_job.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT send_dpd_job.lo -MD -MP -MF $(DEPDIR)/send_dpd_job.Tpo -c -o send_dpd_job.lo `test -f 'processing/jobs/send_dpd_job.c' || echo '$(srcdir)/'`processing/jobs/send_dpd_job.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/send_dpd_job.Tpo $(DEPDIR)/send_dpd_job.Plo @@ -1374,47 +1504,40 @@ inactivity_job.lo: processing/jobs/inactivity_job.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o inactivity_job.lo `test -f 'processing/jobs/inactivity_job.c' || echo '$(srcdir)/'`processing/jobs/inactivity_job.c -authenticator.lo: sa/authenticators/authenticator.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.lo -MD -MP -MF $(DEPDIR)/authenticator.Tpo -c -o authenticator.lo `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/authenticator.Tpo $(DEPDIR)/authenticator.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/authenticator.c' object='authenticator.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o authenticator.lo `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c - -eap_authenticator.lo: sa/authenticators/eap_authenticator.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_authenticator.lo -MD -MP -MF $(DEPDIR)/eap_authenticator.Tpo -c -o eap_authenticator.lo `test -f 'sa/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/eap_authenticator.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/eap_authenticator.Tpo $(DEPDIR)/eap_authenticator.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap_authenticator.c' object='eap_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_authenticator.lo `test -f 'sa/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/eap_authenticator.c - -eap_method.lo: sa/authenticators/eap/eap_method.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_method.lo -MD -MP -MF $(DEPDIR)/eap_method.Tpo -c -o eap_method.lo `test -f 'sa/authenticators/eap/eap_method.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_method.c +eap_method.lo: sa/eap/eap_method.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_method.lo -MD -MP -MF $(DEPDIR)/eap_method.Tpo -c -o eap_method.lo `test -f 'sa/eap/eap_method.c' || echo '$(srcdir)/'`sa/eap/eap_method.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/eap_method.Tpo $(DEPDIR)/eap_method.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_method.c' object='eap_method.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/eap/eap_method.c' object='eap_method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_method.lo `test -f 'sa/authenticators/eap/eap_method.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_method.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_method.lo `test -f 'sa/eap/eap_method.c' || echo '$(srcdir)/'`sa/eap/eap_method.c -eap_manager.lo: sa/authenticators/eap/eap_manager.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_manager.lo -MD -MP -MF $(DEPDIR)/eap_manager.Tpo -c -o eap_manager.lo `test -f 'sa/authenticators/eap/eap_manager.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_manager.c +eap_manager.lo: sa/eap/eap_manager.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_manager.lo -MD -MP -MF $(DEPDIR)/eap_manager.Tpo -c -o eap_manager.lo `test -f 'sa/eap/eap_manager.c' || echo '$(srcdir)/'`sa/eap/eap_manager.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/eap_manager.Tpo $(DEPDIR)/eap_manager.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/eap/eap_manager.c' object='eap_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/eap/eap_manager.c' object='eap_manager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_manager.lo `test -f 'sa/authenticators/eap/eap_manager.c' || echo '$(srcdir)/'`sa/authenticators/eap/eap_manager.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_manager.lo `test -f 'sa/eap/eap_manager.c' || echo '$(srcdir)/'`sa/eap/eap_manager.c -psk_authenticator.lo: sa/authenticators/psk_authenticator.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT psk_authenticator.lo -MD -MP -MF $(DEPDIR)/psk_authenticator.Tpo -c -o psk_authenticator.lo `test -f 'sa/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/psk_authenticator.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/psk_authenticator.Tpo $(DEPDIR)/psk_authenticator.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/psk_authenticator.c' object='psk_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +xauth_method.lo: sa/xauth/xauth_method.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_method.lo -MD -MP -MF $(DEPDIR)/xauth_method.Tpo -c -o xauth_method.lo `test -f 'sa/xauth/xauth_method.c' || echo '$(srcdir)/'`sa/xauth/xauth_method.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_method.Tpo $(DEPDIR)/xauth_method.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/xauth/xauth_method.c' object='xauth_method.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psk_authenticator.lo `test -f 'sa/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/psk_authenticator.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_method.lo `test -f 'sa/xauth/xauth_method.c' || echo '$(srcdir)/'`sa/xauth/xauth_method.c -pubkey_authenticator.lo: sa/authenticators/pubkey_authenticator.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pubkey_authenticator.lo -MD -MP -MF $(DEPDIR)/pubkey_authenticator.Tpo -c -o pubkey_authenticator.lo `test -f 'sa/authenticators/pubkey_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/pubkey_authenticator.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pubkey_authenticator.Tpo $(DEPDIR)/pubkey_authenticator.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticators/pubkey_authenticator.c' object='pubkey_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +xauth_manager.lo: sa/xauth/xauth_manager.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_manager.lo -MD -MP -MF $(DEPDIR)/xauth_manager.Tpo -c -o xauth_manager.lo `test -f 'sa/xauth/xauth_manager.c' || echo '$(srcdir)/'`sa/xauth/xauth_manager.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_manager.Tpo $(DEPDIR)/xauth_manager.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/xauth/xauth_manager.c' object='xauth_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_manager.lo `test -f 'sa/xauth/xauth_manager.c' || echo '$(srcdir)/'`sa/xauth/xauth_manager.c + +authenticator.lo: sa/authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.lo -MD -MP -MF $(DEPDIR)/authenticator.Tpo -c -o authenticator.lo `test -f 'sa/authenticator.c' || echo '$(srcdir)/'`sa/authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/authenticator.Tpo $(DEPDIR)/authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/authenticator.c' object='authenticator.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pubkey_authenticator.lo `test -f 'sa/authenticators/pubkey_authenticator.c' || echo '$(srcdir)/'`sa/authenticators/pubkey_authenticator.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o authenticator.lo `test -f 'sa/authenticator.c' || echo '$(srcdir)/'`sa/authenticator.c child_sa.lo: sa/child_sa.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_sa.lo -MD -MP -MF $(DEPDIR)/child_sa.Tpo -c -o child_sa.lo `test -f 'sa/child_sa.c' || echo '$(srcdir)/'`sa/child_sa.c @@ -1437,6 +1560,13 @@ ike_sa_id.lo: sa/ike_sa_id.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_sa_id.lo `test -f 'sa/ike_sa_id.c' || echo '$(srcdir)/'`sa/ike_sa_id.c +keymat.lo: sa/keymat.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT keymat.lo -MD -MP -MF $(DEPDIR)/keymat.Tpo -c -o keymat.lo `test -f 'sa/keymat.c' || echo '$(srcdir)/'`sa/keymat.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/keymat.Tpo $(DEPDIR)/keymat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/keymat.c' object='keymat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o keymat.lo `test -f 'sa/keymat.c' || echo '$(srcdir)/'`sa/keymat.c + ike_sa_manager.lo: sa/ike_sa_manager.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_sa_manager.lo -MD -MP -MF $(DEPDIR)/ike_sa_manager.Tpo -c -o ike_sa_manager.lo `test -f 'sa/ike_sa_manager.c' || echo '$(srcdir)/'`sa/ike_sa_manager.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_sa_manager.Tpo $(DEPDIR)/ike_sa_manager.Plo @@ -1451,13 +1581,6 @@ task_manager.lo: sa/task_manager.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_manager.lo `test -f 'sa/task_manager.c' || echo '$(srcdir)/'`sa/task_manager.c -keymat.lo: sa/keymat.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT keymat.lo -MD -MP -MF $(DEPDIR)/keymat.Tpo -c -o keymat.lo `test -f 'sa/keymat.c' || echo '$(srcdir)/'`sa/keymat.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/keymat.Tpo $(DEPDIR)/keymat.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/keymat.c' object='keymat.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o keymat.lo `test -f 'sa/keymat.c' || echo '$(srcdir)/'`sa/keymat.c - shunt_manager.lo: sa/shunt_manager.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT shunt_manager.lo -MD -MP -MF $(DEPDIR)/shunt_manager.Tpo -c -o shunt_manager.lo `test -f 'sa/shunt_manager.c' || echo '$(srcdir)/'`sa/shunt_manager.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/shunt_manager.Tpo $(DEPDIR)/shunt_manager.Plo @@ -1472,124 +1595,306 @@ trap_manager.lo: sa/trap_manager.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o trap_manager.lo `test -f 'sa/trap_manager.c' || echo '$(srcdir)/'`sa/trap_manager.c -child_create.lo: sa/tasks/child_create.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_create.lo -MD -MP -MF $(DEPDIR)/child_create.Tpo -c -o child_create.lo `test -f 'sa/tasks/child_create.c' || echo '$(srcdir)/'`sa/tasks/child_create.c +task.lo: sa/task.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.lo -MD -MP -MF $(DEPDIR)/task.Tpo -c -o task.lo `test -f 'sa/task.c' || echo '$(srcdir)/'`sa/task.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/task.Tpo $(DEPDIR)/task.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/task.c' object='task.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task.lo `test -f 'sa/task.c' || echo '$(srcdir)/'`sa/task.c + +keymat_v2.lo: sa/ikev2/keymat_v2.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT keymat_v2.lo -MD -MP -MF $(DEPDIR)/keymat_v2.Tpo -c -o keymat_v2.lo `test -f 'sa/ikev2/keymat_v2.c' || echo '$(srcdir)/'`sa/ikev2/keymat_v2.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/keymat_v2.Tpo $(DEPDIR)/keymat_v2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/keymat_v2.c' object='keymat_v2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o keymat_v2.lo `test -f 'sa/ikev2/keymat_v2.c' || echo '$(srcdir)/'`sa/ikev2/keymat_v2.c + +task_manager_v2.lo: sa/ikev2/task_manager_v2.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_manager_v2.lo -MD -MP -MF $(DEPDIR)/task_manager_v2.Tpo -c -o task_manager_v2.lo `test -f 'sa/ikev2/task_manager_v2.c' || echo '$(srcdir)/'`sa/ikev2/task_manager_v2.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/task_manager_v2.Tpo $(DEPDIR)/task_manager_v2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/task_manager_v2.c' object='task_manager_v2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_manager_v2.lo `test -f 'sa/ikev2/task_manager_v2.c' || echo '$(srcdir)/'`sa/ikev2/task_manager_v2.c + +eap_authenticator.lo: sa/ikev2/authenticators/eap_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT eap_authenticator.lo -MD -MP -MF $(DEPDIR)/eap_authenticator.Tpo -c -o eap_authenticator.lo `test -f 'sa/ikev2/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/eap_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/eap_authenticator.Tpo $(DEPDIR)/eap_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/authenticators/eap_authenticator.c' object='eap_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap_authenticator.lo `test -f 'sa/ikev2/authenticators/eap_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/eap_authenticator.c + +psk_authenticator.lo: sa/ikev2/authenticators/psk_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT psk_authenticator.lo -MD -MP -MF $(DEPDIR)/psk_authenticator.Tpo -c -o psk_authenticator.lo `test -f 'sa/ikev2/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/psk_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/psk_authenticator.Tpo $(DEPDIR)/psk_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/authenticators/psk_authenticator.c' object='psk_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psk_authenticator.lo `test -f 'sa/ikev2/authenticators/psk_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/psk_authenticator.c + +pubkey_authenticator.lo: sa/ikev2/authenticators/pubkey_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pubkey_authenticator.lo -MD -MP -MF $(DEPDIR)/pubkey_authenticator.Tpo -c -o pubkey_authenticator.lo `test -f 'sa/ikev2/authenticators/pubkey_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/pubkey_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pubkey_authenticator.Tpo $(DEPDIR)/pubkey_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/authenticators/pubkey_authenticator.c' object='pubkey_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pubkey_authenticator.lo `test -f 'sa/ikev2/authenticators/pubkey_authenticator.c' || echo '$(srcdir)/'`sa/ikev2/authenticators/pubkey_authenticator.c + +child_create.lo: sa/ikev2/tasks/child_create.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_create.lo -MD -MP -MF $(DEPDIR)/child_create.Tpo -c -o child_create.lo `test -f 'sa/ikev2/tasks/child_create.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_create.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/child_create.Tpo $(DEPDIR)/child_create.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_create.c' object='child_create.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/child_create.c' object='child_create.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_create.lo `test -f 'sa/tasks/child_create.c' || echo '$(srcdir)/'`sa/tasks/child_create.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_create.lo `test -f 'sa/ikev2/tasks/child_create.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_create.c -child_delete.lo: sa/tasks/child_delete.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_delete.lo -MD -MP -MF $(DEPDIR)/child_delete.Tpo -c -o child_delete.lo `test -f 'sa/tasks/child_delete.c' || echo '$(srcdir)/'`sa/tasks/child_delete.c +child_delete.lo: sa/ikev2/tasks/child_delete.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_delete.lo -MD -MP -MF $(DEPDIR)/child_delete.Tpo -c -o child_delete.lo `test -f 'sa/ikev2/tasks/child_delete.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_delete.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/child_delete.Tpo $(DEPDIR)/child_delete.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_delete.c' object='child_delete.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/child_delete.c' object='child_delete.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_delete.lo `test -f 'sa/tasks/child_delete.c' || echo '$(srcdir)/'`sa/tasks/child_delete.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_delete.lo `test -f 'sa/ikev2/tasks/child_delete.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_delete.c -child_rekey.lo: sa/tasks/child_rekey.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_rekey.lo -MD -MP -MF $(DEPDIR)/child_rekey.Tpo -c -o child_rekey.lo `test -f 'sa/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/tasks/child_rekey.c +child_rekey.lo: sa/ikev2/tasks/child_rekey.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT child_rekey.lo -MD -MP -MF $(DEPDIR)/child_rekey.Tpo -c -o child_rekey.lo `test -f 'sa/ikev2/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_rekey.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/child_rekey.Tpo $(DEPDIR)/child_rekey.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/child_rekey.c' object='child_rekey.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/child_rekey.c' object='child_rekey.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_rekey.lo `test -f 'sa/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/tasks/child_rekey.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o child_rekey.lo `test -f 'sa/ikev2/tasks/child_rekey.c' || echo '$(srcdir)/'`sa/ikev2/tasks/child_rekey.c -ike_auth.lo: sa/tasks/ike_auth.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth.lo -MD -MP -MF $(DEPDIR)/ike_auth.Tpo -c -o ike_auth.lo `test -f 'sa/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/tasks/ike_auth.c +ike_auth.lo: sa/ikev2/tasks/ike_auth.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth.lo -MD -MP -MF $(DEPDIR)/ike_auth.Tpo -c -o ike_auth.lo `test -f 'sa/ikev2/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_auth.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_auth.Tpo $(DEPDIR)/ike_auth.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth.c' object='ike_auth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_auth.c' object='ike_auth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth.lo `test -f 'sa/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/tasks/ike_auth.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth.lo `test -f 'sa/ikev2/tasks/ike_auth.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_auth.c -ike_cert_pre.lo: sa/tasks/ike_cert_pre.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert_pre.lo -MD -MP -MF $(DEPDIR)/ike_cert_pre.Tpo -c -o ike_cert_pre.lo `test -f 'sa/tasks/ike_cert_pre.c' || echo '$(srcdir)/'`sa/tasks/ike_cert_pre.c +ike_cert_pre.lo: sa/ikev2/tasks/ike_cert_pre.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert_pre.lo -MD -MP -MF $(DEPDIR)/ike_cert_pre.Tpo -c -o ike_cert_pre.lo `test -f 'sa/ikev2/tasks/ike_cert_pre.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_cert_pre.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_cert_pre.Tpo $(DEPDIR)/ike_cert_pre.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_cert_pre.c' object='ike_cert_pre.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_cert_pre.c' object='ike_cert_pre.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert_pre.lo `test -f 'sa/tasks/ike_cert_pre.c' || echo '$(srcdir)/'`sa/tasks/ike_cert_pre.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert_pre.lo `test -f 'sa/ikev2/tasks/ike_cert_pre.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_cert_pre.c -ike_cert_post.lo: sa/tasks/ike_cert_post.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert_post.lo -MD -MP -MF $(DEPDIR)/ike_cert_post.Tpo -c -o ike_cert_post.lo `test -f 'sa/tasks/ike_cert_post.c' || echo '$(srcdir)/'`sa/tasks/ike_cert_post.c +ike_cert_post.lo: sa/ikev2/tasks/ike_cert_post.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_cert_post.lo -MD -MP -MF $(DEPDIR)/ike_cert_post.Tpo -c -o ike_cert_post.lo `test -f 'sa/ikev2/tasks/ike_cert_post.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_cert_post.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_cert_post.Tpo $(DEPDIR)/ike_cert_post.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_cert_post.c' object='ike_cert_post.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_cert_post.c' object='ike_cert_post.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert_post.lo `test -f 'sa/tasks/ike_cert_post.c' || echo '$(srcdir)/'`sa/tasks/ike_cert_post.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_cert_post.lo `test -f 'sa/ikev2/tasks/ike_cert_post.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_cert_post.c -ike_config.lo: sa/tasks/ike_config.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_config.lo -MD -MP -MF $(DEPDIR)/ike_config.Tpo -c -o ike_config.lo `test -f 'sa/tasks/ike_config.c' || echo '$(srcdir)/'`sa/tasks/ike_config.c +ike_config.lo: sa/ikev2/tasks/ike_config.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_config.lo -MD -MP -MF $(DEPDIR)/ike_config.Tpo -c -o ike_config.lo `test -f 'sa/ikev2/tasks/ike_config.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_config.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_config.Tpo $(DEPDIR)/ike_config.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_config.c' object='ike_config.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_config.c' object='ike_config.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_config.lo `test -f 'sa/tasks/ike_config.c' || echo '$(srcdir)/'`sa/tasks/ike_config.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_config.lo `test -f 'sa/ikev2/tasks/ike_config.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_config.c -ike_delete.lo: sa/tasks/ike_delete.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_delete.lo -MD -MP -MF $(DEPDIR)/ike_delete.Tpo -c -o ike_delete.lo `test -f 'sa/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/tasks/ike_delete.c +ike_delete.lo: sa/ikev2/tasks/ike_delete.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_delete.lo -MD -MP -MF $(DEPDIR)/ike_delete.Tpo -c -o ike_delete.lo `test -f 'sa/ikev2/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_delete.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_delete.Tpo $(DEPDIR)/ike_delete.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_delete.c' object='ike_delete.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_delete.c' object='ike_delete.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_delete.lo `test -f 'sa/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/tasks/ike_delete.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_delete.lo `test -f 'sa/ikev2/tasks/ike_delete.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_delete.c -ike_dpd.lo: sa/tasks/ike_dpd.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_dpd.lo -MD -MP -MF $(DEPDIR)/ike_dpd.Tpo -c -o ike_dpd.lo `test -f 'sa/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/tasks/ike_dpd.c +ike_dpd.lo: sa/ikev2/tasks/ike_dpd.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_dpd.lo -MD -MP -MF $(DEPDIR)/ike_dpd.Tpo -c -o ike_dpd.lo `test -f 'sa/ikev2/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_dpd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_dpd.Tpo $(DEPDIR)/ike_dpd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_dpd.c' object='ike_dpd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_dpd.c' object='ike_dpd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_dpd.lo `test -f 'sa/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/tasks/ike_dpd.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_dpd.lo `test -f 'sa/ikev2/tasks/ike_dpd.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_dpd.c -ike_init.lo: sa/tasks/ike_init.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_init.lo -MD -MP -MF $(DEPDIR)/ike_init.Tpo -c -o ike_init.lo `test -f 'sa/tasks/ike_init.c' || echo '$(srcdir)/'`sa/tasks/ike_init.c +ike_init.lo: sa/ikev2/tasks/ike_init.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_init.lo -MD -MP -MF $(DEPDIR)/ike_init.Tpo -c -o ike_init.lo `test -f 'sa/ikev2/tasks/ike_init.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_init.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_init.Tpo $(DEPDIR)/ike_init.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_init.c' object='ike_init.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_init.c' object='ike_init.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_init.lo `test -f 'sa/tasks/ike_init.c' || echo '$(srcdir)/'`sa/tasks/ike_init.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_init.lo `test -f 'sa/ikev2/tasks/ike_init.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_init.c -ike_natd.lo: sa/tasks/ike_natd.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_natd.lo -MD -MP -MF $(DEPDIR)/ike_natd.Tpo -c -o ike_natd.lo `test -f 'sa/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/tasks/ike_natd.c +ike_natd.lo: sa/ikev2/tasks/ike_natd.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_natd.lo -MD -MP -MF $(DEPDIR)/ike_natd.Tpo -c -o ike_natd.lo `test -f 'sa/ikev2/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_natd.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_natd.Tpo $(DEPDIR)/ike_natd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_natd.c' object='ike_natd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_natd.c' object='ike_natd.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_natd.lo `test -f 'sa/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/tasks/ike_natd.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_natd.lo `test -f 'sa/ikev2/tasks/ike_natd.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_natd.c -ike_mobike.lo: sa/tasks/ike_mobike.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.lo -MD -MP -MF $(DEPDIR)/ike_mobike.Tpo -c -o ike_mobike.lo `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c +ike_mobike.lo: sa/ikev2/tasks/ike_mobike.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.lo -MD -MP -MF $(DEPDIR)/ike_mobike.Tpo -c -o ike_mobike.lo `test -f 'sa/ikev2/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_mobike.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_mobike.Tpo $(DEPDIR)/ike_mobike.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_mobike.c' object='ike_mobike.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_mobike.c' object='ike_mobike.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_mobike.lo `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_mobike.lo `test -f 'sa/ikev2/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_mobike.c -ike_rekey.lo: sa/tasks/ike_rekey.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.lo -MD -MP -MF $(DEPDIR)/ike_rekey.Tpo -c -o ike_rekey.lo `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c +ike_rekey.lo: sa/ikev2/tasks/ike_rekey.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.lo -MD -MP -MF $(DEPDIR)/ike_rekey.Tpo -c -o ike_rekey.lo `test -f 'sa/ikev2/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_rekey.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_rekey.Tpo $(DEPDIR)/ike_rekey.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_rekey.c' object='ike_rekey.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_rekey.c' object='ike_rekey.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_rekey.lo `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_rekey.lo `test -f 'sa/ikev2/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_rekey.c -ike_reauth.lo: sa/tasks/ike_reauth.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.lo -MD -MP -MF $(DEPDIR)/ike_reauth.Tpo -c -o ike_reauth.lo `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c +ike_reauth.lo: sa/ikev2/tasks/ike_reauth.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.lo -MD -MP -MF $(DEPDIR)/ike_reauth.Tpo -c -o ike_reauth.lo `test -f 'sa/ikev2/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_reauth.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_reauth.Tpo $(DEPDIR)/ike_reauth.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_reauth.c' object='ike_reauth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_reauth.c' object='ike_reauth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_reauth.lo `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_reauth.lo `test -f 'sa/ikev2/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_reauth.c -ike_auth_lifetime.lo: sa/tasks/ike_auth_lifetime.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.lo -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.lo `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c +ike_auth_lifetime.lo: sa/ikev2/tasks/ike_auth_lifetime.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_auth_lifetime.lo -MD -MP -MF $(DEPDIR)/ike_auth_lifetime.Tpo -c -o ike_auth_lifetime.lo `test -f 'sa/ikev2/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_auth_lifetime.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_auth_lifetime.Tpo $(DEPDIR)/ike_auth_lifetime.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_auth_lifetime.c' object='ike_auth_lifetime.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth_lifetime.lo `test -f 'sa/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/tasks/ike_auth_lifetime.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_auth_lifetime.lo `test -f 'sa/ikev2/tasks/ike_auth_lifetime.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_auth_lifetime.c -ike_vendor.lo: sa/tasks/ike_vendor.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_vendor.lo -MD -MP -MF $(DEPDIR)/ike_vendor.Tpo -c -o ike_vendor.lo `test -f 'sa/tasks/ike_vendor.c' || echo '$(srcdir)/'`sa/tasks/ike_vendor.c +ike_vendor.lo: sa/ikev2/tasks/ike_vendor.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_vendor.lo -MD -MP -MF $(DEPDIR)/ike_vendor.Tpo -c -o ike_vendor.lo `test -f 'sa/ikev2/tasks/ike_vendor.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_vendor.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_vendor.Tpo $(DEPDIR)/ike_vendor.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_vendor.c' object='ike_vendor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_vendor.c' object='ike_vendor.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_vendor.lo `test -f 'sa/tasks/ike_vendor.c' || echo '$(srcdir)/'`sa/tasks/ike_vendor.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_vendor.lo `test -f 'sa/ikev2/tasks/ike_vendor.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_vendor.c -task.lo: sa/tasks/task.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.lo -MD -MP -MF $(DEPDIR)/task.Tpo -c -o task.lo `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/task.Tpo $(DEPDIR)/task.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/task.c' object='task.lo' libtool=yes @AMDEPBACKSLASH@ +keymat_v1.lo: sa/ikev1/keymat_v1.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT keymat_v1.lo -MD -MP -MF $(DEPDIR)/keymat_v1.Tpo -c -o keymat_v1.lo `test -f 'sa/ikev1/keymat_v1.c' || echo '$(srcdir)/'`sa/ikev1/keymat_v1.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/keymat_v1.Tpo $(DEPDIR)/keymat_v1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/keymat_v1.c' object='keymat_v1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o keymat_v1.lo `test -f 'sa/ikev1/keymat_v1.c' || echo '$(srcdir)/'`sa/ikev1/keymat_v1.c + +task_manager_v1.lo: sa/ikev1/task_manager_v1.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task_manager_v1.lo -MD -MP -MF $(DEPDIR)/task_manager_v1.Tpo -c -o task_manager_v1.lo `test -f 'sa/ikev1/task_manager_v1.c' || echo '$(srcdir)/'`sa/ikev1/task_manager_v1.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/task_manager_v1.Tpo $(DEPDIR)/task_manager_v1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/task_manager_v1.c' object='task_manager_v1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task_manager_v1.lo `test -f 'sa/ikev1/task_manager_v1.c' || echo '$(srcdir)/'`sa/ikev1/task_manager_v1.c + +psk_v1_authenticator.lo: sa/ikev1/authenticators/psk_v1_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT psk_v1_authenticator.lo -MD -MP -MF $(DEPDIR)/psk_v1_authenticator.Tpo -c -o psk_v1_authenticator.lo `test -f 'sa/ikev1/authenticators/psk_v1_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/psk_v1_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/psk_v1_authenticator.Tpo $(DEPDIR)/psk_v1_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/authenticators/psk_v1_authenticator.c' object='psk_v1_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o psk_v1_authenticator.lo `test -f 'sa/ikev1/authenticators/psk_v1_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/psk_v1_authenticator.c + +pubkey_v1_authenticator.lo: sa/ikev1/authenticators/pubkey_v1_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pubkey_v1_authenticator.lo -MD -MP -MF $(DEPDIR)/pubkey_v1_authenticator.Tpo -c -o pubkey_v1_authenticator.lo `test -f 'sa/ikev1/authenticators/pubkey_v1_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/pubkey_v1_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pubkey_v1_authenticator.Tpo $(DEPDIR)/pubkey_v1_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/authenticators/pubkey_v1_authenticator.c' object='pubkey_v1_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pubkey_v1_authenticator.lo `test -f 'sa/ikev1/authenticators/pubkey_v1_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/pubkey_v1_authenticator.c + +hybrid_authenticator.lo: sa/ikev1/authenticators/hybrid_authenticator.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hybrid_authenticator.lo -MD -MP -MF $(DEPDIR)/hybrid_authenticator.Tpo -c -o hybrid_authenticator.lo `test -f 'sa/ikev1/authenticators/hybrid_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/hybrid_authenticator.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hybrid_authenticator.Tpo $(DEPDIR)/hybrid_authenticator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/authenticators/hybrid_authenticator.c' object='hybrid_authenticator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hybrid_authenticator.lo `test -f 'sa/ikev1/authenticators/hybrid_authenticator.c' || echo '$(srcdir)/'`sa/ikev1/authenticators/hybrid_authenticator.c + +phase1.lo: sa/ikev1/phase1.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT phase1.lo -MD -MP -MF $(DEPDIR)/phase1.Tpo -c -o phase1.lo `test -f 'sa/ikev1/phase1.c' || echo '$(srcdir)/'`sa/ikev1/phase1.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/phase1.Tpo $(DEPDIR)/phase1.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/phase1.c' object='phase1.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o phase1.lo `test -f 'sa/ikev1/phase1.c' || echo '$(srcdir)/'`sa/ikev1/phase1.c + +main_mode.lo: sa/ikev1/tasks/main_mode.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT main_mode.lo -MD -MP -MF $(DEPDIR)/main_mode.Tpo -c -o main_mode.lo `test -f 'sa/ikev1/tasks/main_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/main_mode.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/main_mode.Tpo $(DEPDIR)/main_mode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/main_mode.c' object='main_mode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o main_mode.lo `test -f 'sa/ikev1/tasks/main_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/main_mode.c + +aggressive_mode.lo: sa/ikev1/tasks/aggressive_mode.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT aggressive_mode.lo -MD -MP -MF $(DEPDIR)/aggressive_mode.Tpo -c -o aggressive_mode.lo `test -f 'sa/ikev1/tasks/aggressive_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/aggressive_mode.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/aggressive_mode.Tpo $(DEPDIR)/aggressive_mode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/aggressive_mode.c' object='aggressive_mode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o aggressive_mode.lo `test -f 'sa/ikev1/tasks/aggressive_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/aggressive_mode.c + +informational.lo: sa/ikev1/tasks/informational.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT informational.lo -MD -MP -MF $(DEPDIR)/informational.Tpo -c -o informational.lo `test -f 'sa/ikev1/tasks/informational.c' || echo '$(srcdir)/'`sa/ikev1/tasks/informational.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/informational.Tpo $(DEPDIR)/informational.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/informational.c' object='informational.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o informational.lo `test -f 'sa/ikev1/tasks/informational.c' || echo '$(srcdir)/'`sa/ikev1/tasks/informational.c + +isakmp_cert_pre.lo: sa/ikev1/tasks/isakmp_cert_pre.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_cert_pre.lo -MD -MP -MF $(DEPDIR)/isakmp_cert_pre.Tpo -c -o isakmp_cert_pre.lo `test -f 'sa/ikev1/tasks/isakmp_cert_pre.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_cert_pre.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_cert_pre.Tpo $(DEPDIR)/isakmp_cert_pre.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_cert_pre.c' object='isakmp_cert_pre.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_cert_pre.lo `test -f 'sa/ikev1/tasks/isakmp_cert_pre.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_cert_pre.c + +isakmp_cert_post.lo: sa/ikev1/tasks/isakmp_cert_post.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_cert_post.lo -MD -MP -MF $(DEPDIR)/isakmp_cert_post.Tpo -c -o isakmp_cert_post.lo `test -f 'sa/ikev1/tasks/isakmp_cert_post.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_cert_post.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_cert_post.Tpo $(DEPDIR)/isakmp_cert_post.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_cert_post.c' object='isakmp_cert_post.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_cert_post.lo `test -f 'sa/ikev1/tasks/isakmp_cert_post.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_cert_post.c + +isakmp_natd.lo: sa/ikev1/tasks/isakmp_natd.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_natd.lo -MD -MP -MF $(DEPDIR)/isakmp_natd.Tpo -c -o isakmp_natd.lo `test -f 'sa/ikev1/tasks/isakmp_natd.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_natd.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_natd.Tpo $(DEPDIR)/isakmp_natd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_natd.c' object='isakmp_natd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_natd.lo `test -f 'sa/ikev1/tasks/isakmp_natd.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_natd.c + +isakmp_vendor.lo: sa/ikev1/tasks/isakmp_vendor.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_vendor.lo -MD -MP -MF $(DEPDIR)/isakmp_vendor.Tpo -c -o isakmp_vendor.lo `test -f 'sa/ikev1/tasks/isakmp_vendor.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_vendor.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_vendor.Tpo $(DEPDIR)/isakmp_vendor.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_vendor.c' object='isakmp_vendor.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_vendor.lo `test -f 'sa/ikev1/tasks/isakmp_vendor.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_vendor.c + +isakmp_delete.lo: sa/ikev1/tasks/isakmp_delete.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_delete.lo -MD -MP -MF $(DEPDIR)/isakmp_delete.Tpo -c -o isakmp_delete.lo `test -f 'sa/ikev1/tasks/isakmp_delete.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_delete.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_delete.Tpo $(DEPDIR)/isakmp_delete.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_delete.c' object='isakmp_delete.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_delete.lo `test -f 'sa/ikev1/tasks/isakmp_delete.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_delete.c + +isakmp_dpd.lo: sa/ikev1/tasks/isakmp_dpd.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isakmp_dpd.lo -MD -MP -MF $(DEPDIR)/isakmp_dpd.Tpo -c -o isakmp_dpd.lo `test -f 'sa/ikev1/tasks/isakmp_dpd.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_dpd.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/isakmp_dpd.Tpo $(DEPDIR)/isakmp_dpd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/isakmp_dpd.c' object='isakmp_dpd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isakmp_dpd.lo `test -f 'sa/ikev1/tasks/isakmp_dpd.c' || echo '$(srcdir)/'`sa/ikev1/tasks/isakmp_dpd.c + +xauth.lo: sa/ikev1/tasks/xauth.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth.lo -MD -MP -MF $(DEPDIR)/xauth.Tpo -c -o xauth.lo `test -f 'sa/ikev1/tasks/xauth.c' || echo '$(srcdir)/'`sa/ikev1/tasks/xauth.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth.Tpo $(DEPDIR)/xauth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/xauth.c' object='xauth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth.lo `test -f 'sa/ikev1/tasks/xauth.c' || echo '$(srcdir)/'`sa/ikev1/tasks/xauth.c + +quick_mode.lo: sa/ikev1/tasks/quick_mode.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT quick_mode.lo -MD -MP -MF $(DEPDIR)/quick_mode.Tpo -c -o quick_mode.lo `test -f 'sa/ikev1/tasks/quick_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/quick_mode.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/quick_mode.Tpo $(DEPDIR)/quick_mode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/quick_mode.c' object='quick_mode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o quick_mode.lo `test -f 'sa/ikev1/tasks/quick_mode.c' || echo '$(srcdir)/'`sa/ikev1/tasks/quick_mode.c + +quick_delete.lo: sa/ikev1/tasks/quick_delete.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT quick_delete.lo -MD -MP -MF $(DEPDIR)/quick_delete.Tpo -c -o quick_delete.lo `test -f 'sa/ikev1/tasks/quick_delete.c' || echo '$(srcdir)/'`sa/ikev1/tasks/quick_delete.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/quick_delete.Tpo $(DEPDIR)/quick_delete.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/quick_delete.c' object='quick_delete.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o quick_delete.lo `test -f 'sa/ikev1/tasks/quick_delete.c' || echo '$(srcdir)/'`sa/ikev1/tasks/quick_delete.c + +mode_config.lo: sa/ikev1/tasks/mode_config.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mode_config.lo -MD -MP -MF $(DEPDIR)/mode_config.Tpo -c -o mode_config.lo `test -f 'sa/ikev1/tasks/mode_config.c' || echo '$(srcdir)/'`sa/ikev1/tasks/mode_config.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mode_config.Tpo $(DEPDIR)/mode_config.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev1/tasks/mode_config.c' object='mode_config.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mode_config.lo `test -f 'sa/ikev1/tasks/mode_config.c' || echo '$(srcdir)/'`sa/ikev1/tasks/mode_config.c + +dpd_timeout_job.lo: processing/jobs/dpd_timeout_job.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT dpd_timeout_job.lo -MD -MP -MF $(DEPDIR)/dpd_timeout_job.Tpo -c -o dpd_timeout_job.lo `test -f 'processing/jobs/dpd_timeout_job.c' || echo '$(srcdir)/'`processing/jobs/dpd_timeout_job.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/dpd_timeout_job.Tpo $(DEPDIR)/dpd_timeout_job.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/dpd_timeout_job.c' object='dpd_timeout_job.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o dpd_timeout_job.lo `test -f 'processing/jobs/dpd_timeout_job.c' || echo '$(srcdir)/'`processing/jobs/dpd_timeout_job.c + +adopt_children_job.lo: processing/jobs/adopt_children_job.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT adopt_children_job.lo -MD -MP -MF $(DEPDIR)/adopt_children_job.Tpo -c -o adopt_children_job.lo `test -f 'processing/jobs/adopt_children_job.c' || echo '$(srcdir)/'`processing/jobs/adopt_children_job.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/adopt_children_job.Tpo $(DEPDIR)/adopt_children_job.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/adopt_children_job.c' object='adopt_children_job.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o task.lo `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o adopt_children_job.lo `test -f 'processing/jobs/adopt_children_job.c' || echo '$(srcdir)/'`processing/jobs/adopt_children_job.c endpoint_notify.lo: encoding/payloads/endpoint_notify.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT endpoint_notify.lo -MD -MP -MF $(DEPDIR)/endpoint_notify.Tpo -c -o endpoint_notify.lo `test -f 'encoding/payloads/endpoint_notify.c' || echo '$(srcdir)/'`encoding/payloads/endpoint_notify.c @@ -1612,26 +1917,26 @@ mediation_job.lo: processing/jobs/mediation_job.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mediation_job.lo `test -f 'processing/jobs/mediation_job.c' || echo '$(srcdir)/'`processing/jobs/mediation_job.c -connect_manager.lo: sa/connect_manager.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT connect_manager.lo -MD -MP -MF $(DEPDIR)/connect_manager.Tpo -c -o connect_manager.lo `test -f 'sa/connect_manager.c' || echo '$(srcdir)/'`sa/connect_manager.c +connect_manager.lo: sa/ikev2/connect_manager.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT connect_manager.lo -MD -MP -MF $(DEPDIR)/connect_manager.Tpo -c -o connect_manager.lo `test -f 'sa/ikev2/connect_manager.c' || echo '$(srcdir)/'`sa/ikev2/connect_manager.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/connect_manager.Tpo $(DEPDIR)/connect_manager.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/connect_manager.c' object='connect_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/connect_manager.c' object='connect_manager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o connect_manager.lo `test -f 'sa/connect_manager.c' || echo '$(srcdir)/'`sa/connect_manager.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o connect_manager.lo `test -f 'sa/ikev2/connect_manager.c' || echo '$(srcdir)/'`sa/ikev2/connect_manager.c -mediation_manager.lo: sa/mediation_manager.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mediation_manager.lo -MD -MP -MF $(DEPDIR)/mediation_manager.Tpo -c -o mediation_manager.lo `test -f 'sa/mediation_manager.c' || echo '$(srcdir)/'`sa/mediation_manager.c +mediation_manager.lo: sa/ikev2/mediation_manager.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mediation_manager.lo -MD -MP -MF $(DEPDIR)/mediation_manager.Tpo -c -o mediation_manager.lo `test -f 'sa/ikev2/mediation_manager.c' || echo '$(srcdir)/'`sa/ikev2/mediation_manager.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mediation_manager.Tpo $(DEPDIR)/mediation_manager.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/mediation_manager.c' object='mediation_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/mediation_manager.c' object='mediation_manager.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mediation_manager.lo `test -f 'sa/mediation_manager.c' || echo '$(srcdir)/'`sa/mediation_manager.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mediation_manager.lo `test -f 'sa/ikev2/mediation_manager.c' || echo '$(srcdir)/'`sa/ikev2/mediation_manager.c -ike_me.lo: sa/tasks/ike_me.c -@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_me.lo -MD -MP -MF $(DEPDIR)/ike_me.Tpo -c -o ike_me.lo `test -f 'sa/tasks/ike_me.c' || echo '$(srcdir)/'`sa/tasks/ike_me.c +ike_me.lo: sa/ikev2/tasks/ike_me.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_me.lo -MD -MP -MF $(DEPDIR)/ike_me.Tpo -c -o ike_me.lo `test -f 'sa/ikev2/tasks/ike_me.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_me.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ike_me.Tpo $(DEPDIR)/ike_me.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_me.c' object='ike_me.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/ikev2/tasks/ike_me.c' object='ike_me.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_me.lo `test -f 'sa/tasks/ike_me.c' || echo '$(srcdir)/'`sa/tasks/ike_me.c +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_me.lo `test -f 'sa/ikev2/tasks/ike_me.c' || echo '$(srcdir)/'`sa/ikev2/tasks/ike_me.c mostlyclean-libtool: -rm -f *.lo diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index bf0ab2286..1f9592e6e 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,8 +20,8 @@ #include #include -#include #include +#include typedef struct private_bus_t private_bus_t; @@ -34,15 +35,33 @@ struct private_bus_t { bus_t public; /** - * List of registered listeners as entry_t's + * List of registered listeners as entry_t. */ linked_list_t *listeners; /** - * mutex to synchronize active listeners, recursively + * List of registered loggers for each log group as log_entry_t. + * Loggers are ordered by descending log level. + * The extra list stores all loggers so we can properly unregister them. + */ + linked_list_t *loggers[DBG_MAX + 1]; + + /** + * Maximum log level of any registered logger for each log group. + * This allows to check quickly if a log message has to be logged at all. + */ + level_t max_level[DBG_MAX + 1]; + + /** + * Mutex for the list of listeners, recursively. */ mutex_t *mutex; + /** + * Read-write lock for the list of loggers. + */ + rwlock_t *log_lock; + /** * Thread local storage the threads IKE_SA */ @@ -52,7 +71,7 @@ struct private_bus_t { typedef struct entry_t entry_t; /** - * a listener entry, either active or passive + * a listener entry */ struct entry_t { @@ -61,51 +80,43 @@ struct entry_t { */ listener_t *listener; - /** - * is this a active listen() call with a blocking thread - */ - bool blocker; - /** * are we currently calling this listener */ int calling; - /** - * condvar where active listeners wait - */ - condvar_t *condvar; }; +typedef struct log_entry_t log_entry_t; + /** - * create a listener entry + * a logger entry */ -static entry_t *entry_create(listener_t *listener, bool blocker) -{ - entry_t *this = malloc_thing(entry_t); +struct log_entry_t { - this->listener = listener; - this->blocker = blocker; - this->calling = 0; - this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); + /** + * registered logger interface + */ + logger_t *logger; - return this; -} + /** + * registered log levels per group + */ + level_t levels[DBG_MAX]; -/** - * destroy an entry_t - */ -static void entry_destroy(entry_t *entry) -{ - entry->condvar->destroy(entry->condvar); - free(entry); -} +}; METHOD(bus_t, add_listener, void, private_bus_t *this, listener_t *listener) { + entry_t *entry; + + INIT(entry, + .listener = listener, + ); + this->mutex->lock(this->mutex); - this->listeners->insert_last(this->listeners, entry_create(listener, FALSE)); + this->listeners->insert_last(this->listeners, entry); this->mutex->unlock(this->mutex); } @@ -122,7 +133,7 @@ METHOD(bus_t, remove_listener, void, if (entry->listener == listener) { this->listeners->remove_at(this->listeners, enumerator); - entry_destroy(entry); + free(entry); break; } } @@ -130,74 +141,107 @@ METHOD(bus_t, remove_listener, void, this->mutex->unlock(this->mutex); } -typedef struct cleanup_data_t cleanup_data_t; - /** - * data to remove a listener using thread_cleanup_t handler + * Register a logger on the given log group according to the requested level */ -struct cleanup_data_t { - /** bus instance */ - private_bus_t *this; - /** listener entry */ - entry_t *entry; -}; - -/** - * thread_cleanup_t handler to remove a listener - */ -static void listener_cleanup(cleanup_data_t *data) +static inline void register_logger(private_bus_t *this, debug_t group, + log_entry_t *entry) { - data->this->listeners->remove(data->this->listeners, data->entry, NULL); - entry_destroy(data->entry); + enumerator_t *enumerator; + linked_list_t *loggers; + log_entry_t *current; + level_t level; + + loggers = this->loggers[group]; + level = entry->levels[group]; + + enumerator = loggers->create_enumerator(loggers); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->levels[group] <= level) + { + break; + } + } + loggers->insert_before(loggers, enumerator, entry); + enumerator->destroy(enumerator); + + this->max_level[group] = max(this->max_level[group], level); } -METHOD(bus_t, listen_, bool, - private_bus_t *this, listener_t *listener, job_t *job, u_int timeout) +/** + * Unregister a logger from all log groups (destroys the log_entry_t) + */ +static inline void unregister_logger(private_bus_t *this, logger_t *logger) { - bool old, timed_out = FALSE; - cleanup_data_t data; - timeval_t tv, add; + enumerator_t *enumerator; + linked_list_t *loggers; + log_entry_t *entry, *found = NULL; - if (timeout) + loggers = this->loggers[DBG_MAX]; + enumerator = loggers->create_enumerator(loggers); + while (enumerator->enumerate(enumerator, &entry)) { - add.tv_sec = timeout / 1000; - add.tv_usec = (timeout - (add.tv_sec * 1000)) * 1000; - time_monotonic(&tv); - timeradd(&tv, &add, &tv); + if (entry->logger == logger) + { + loggers->remove_at(loggers, enumerator); + found = entry; + break; + } } + enumerator->destroy(enumerator); - data.this = this; - data.entry = entry_create(listener, TRUE); - - this->mutex->lock(this->mutex); - this->listeners->insert_last(this->listeners, data.entry); - lib->processor->queue_job(lib->processor, job); - thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); - thread_cleanup_push((thread_cleanup_t)listener_cleanup, &data); - old = thread_cancelability(TRUE); - while (data.entry->blocker) + if (found) { - if (timeout) + debug_t group; + for (group = 0; group < DBG_MAX; group++) { - if (data.entry->condvar->timed_wait_abs(data.entry->condvar, - this->mutex, tv)) + if (found->levels[group] > LEVEL_SILENT) { - this->listeners->remove(this->listeners, data.entry, NULL); - timed_out = TRUE; - break; + loggers = this->loggers[group]; + loggers->remove(loggers, found, NULL); + + this->max_level[group] = LEVEL_SILENT; + if (loggers->get_first(loggers, (void**)&entry) == SUCCESS) + { + this->max_level[group] = entry->levels[group]; + } } } - else + free(found); + } +} + +METHOD(bus_t, add_logger, void, + private_bus_t *this, logger_t *logger) +{ + log_entry_t *entry; + debug_t group; + + INIT(entry, + .logger = logger, + ); + + this->log_lock->write_lock(this->log_lock); + unregister_logger(this, logger); + for (group = 0; group < DBG_MAX; group++) + { + entry->levels[group] = logger->get_level(logger, group); + if (entry->levels[group] > LEVEL_SILENT) { - data.entry->condvar->wait(data.entry->condvar, this->mutex); + register_logger(this, group, entry); } } - thread_cancelability(old); - thread_cleanup_pop(FALSE); - /* unlock mutex */ - thread_cleanup_pop(TRUE); - entry_destroy(data.entry); - return timed_out; + this->loggers[DBG_MAX]->insert_last(this->loggers[DBG_MAX], entry); + this->log_lock->unlock(this->log_lock); +} + +METHOD(bus_t, remove_logger, void, + private_bus_t *this, logger_t *logger) +{ + this->log_lock->write_lock(this->log_lock); + unregister_logger(this, logger); + this->log_lock->unlock(this->log_lock); } METHOD(bus_t, set_sa, void, @@ -224,66 +268,61 @@ typedef struct { debug_t group; /** debug level */ level_t level; - /** format string */ - char *format; - /** argument list */ - va_list args; + /** message */ + char *message; } log_data_t; /** - * listener->log() invocation as a list remove callback + * logger->log() invocation as a invoke_function callback */ -static bool log_cb(entry_t *entry, log_data_t *data) +static void log_cb(log_entry_t *entry, log_data_t *data) { - va_list args; - - if (entry->calling || !entry->listener->log) - { /* avoid recursive calls */ - return FALSE; - } - entry->calling++; - va_copy(args, data->args); - if (!entry->listener->log(entry->listener, data->group, data->level, - data->thread, data->ike_sa, data->format, args)) + if (entry->levels[data->group] < data->level) { - if (entry->blocker) - { - entry->blocker = FALSE; - entry->condvar->signal(entry->condvar); - entry->calling--; - } - else - { - entry_destroy(entry); - } - va_end(args); - return TRUE; + return; } - va_end(args); - entry->calling--; - return FALSE; + entry->logger->log(entry->logger, data->group, data->level, + data->thread, data->ike_sa, data->message); } METHOD(bus_t, vlog, void, private_bus_t *this, debug_t group, level_t level, char* format, va_list args) { - log_data_t data; - - data.ike_sa = this->thread_sa->get(this->thread_sa); - data.thread = thread_current_id(); - data.group = group; - data.level = level; - data.format = format; - va_copy(data.args, args); - - this->mutex->lock(this->mutex); - /* We use the remove() method to invoke all listeners. This is cheap and - * does not require an allocation for this performance critical function. */ - this->listeners->remove(this->listeners, &data, (void*)log_cb); - this->mutex->unlock(this->mutex); - - va_end(data.args); + this->log_lock->read_lock(this->log_lock); + if (this->max_level[group] >= level) + { + linked_list_t *loggers = this->loggers[group]; + log_data_t data; + va_list copy; + char buf[1024]; + ssize_t len; + + data.ike_sa = this->thread_sa->get(this->thread_sa); + data.thread = thread_current_id(); + data.group = group; + data.level = level; + data.message = buf; + + va_copy(copy, args); + len = vsnprintf(data.message, sizeof(buf), format, copy); + va_end(copy); + if (len >= sizeof(buf)) + { + data.message = malloc(len); + len = vsnprintf(data.message, len, format, args); + } + if (len > 0) + { + loggers->invoke_function(loggers, (linked_list_invoke_t)log_cb, + &data); + } + if (data.message != buf) + { + free(data.message); + } + } + this->log_lock->unlock(this->log_lock); } METHOD(bus_t, log_, void, @@ -299,19 +338,11 @@ METHOD(bus_t, log_, void, /** * unregister a listener */ -static void unregister_listener(private_bus_t *this, entry_t *entry, - enumerator_t *enumerator) +static inline void unregister_listener(private_bus_t *this, entry_t *entry, + enumerator_t *enumerator) { - if (entry->blocker) - { - entry->blocker = FALSE; - entry->condvar->signal(entry->condvar); - } - else - { - entry_destroy(entry); - } this->listeners->remove_at(this->listeners, enumerator); + free(entry); } METHOD(bus_t, alert, void, @@ -406,7 +437,7 @@ METHOD(bus_t, child_state_change, void, } METHOD(bus_t, message, void, - private_bus_t *this, message_t *message, bool incoming) + private_bus_t *this, message_t *message, bool incoming, bool plain) { enumerator_t *enumerator; ike_sa_t *ike_sa; @@ -425,7 +456,7 @@ METHOD(bus_t, message, void, } entry->calling++; keep = entry->listener->message(entry->listener, ike_sa, - message, incoming); + message, incoming, plain); entry->calling--; if (!keep) { @@ -438,7 +469,8 @@ METHOD(bus_t, message, void, METHOD(bus_t, ike_keys, void, private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey) + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared) { enumerator_t *enumerator; entry_t *entry; @@ -453,8 +485,8 @@ METHOD(bus_t, ike_keys, void, continue; } entry->calling++; - keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, - nonce_i, nonce_r, rekey); + keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other, + nonce_i, nonce_r, rekey, shared); entry->calling--; if (!keep) { @@ -485,8 +517,8 @@ METHOD(bus_t, child_keys, void, continue; } entry->calling++; - keep = entry->listener->child_keys(entry->listener, ike_sa, child_sa, - initiator, dh, nonce_i, nonce_r); + keep = entry->listener->child_keys(entry->listener, ike_sa, + child_sa, initiator, dh, nonce_i, nonce_r); entry->calling--; if (!keep) { @@ -547,7 +579,8 @@ METHOD(bus_t, child_rekey, void, continue; } entry->calling++; - keep = entry->listener->child_rekey(entry->listener, ike_sa, old, new); + keep = entry->listener->child_rekey(entry->listener, ike_sa, + old, new); entry->calling--; if (!keep) { @@ -626,6 +659,33 @@ METHOD(bus_t, ike_rekey, void, this->mutex->unlock(this->mutex); } +METHOD(bus_t, ike_reestablish, void, + private_bus_t *this, ike_sa_t *old, ike_sa_t *new) +{ + enumerator_t *enumerator; + entry_t *entry; + bool keep; + + this->mutex->lock(this->mutex); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->calling || !entry->listener->ike_reestablish) + { + continue; + } + entry->calling++; + keep = entry->listener->ike_reestablish(entry->listener, old, new); + entry->calling--; + if (!keep) + { + unregister_listener(this, entry, enumerator); + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); +} + METHOD(bus_t, authorize, bool, private_bus_t *this, bool final) { @@ -697,9 +757,17 @@ METHOD(bus_t, narrow, void, METHOD(bus_t, destroy, void, private_bus_t *this) { + debug_t group; + for (group = 0; group < DBG_MAX; group++) + { + this->loggers[group]->destroy(this->loggers[group]); + } + this->loggers[DBG_MAX]->destroy_function(this->loggers[DBG_MAX], + (void*)free); + this->listeners->destroy_function(this->listeners, (void*)free); this->thread_sa->destroy(this->thread_sa); + this->log_lock->destroy(this->log_lock); this->mutex->destroy(this->mutex); - this->listeners->destroy_function(this->listeners, (void*)entry_destroy); free(this); } @@ -709,12 +777,14 @@ METHOD(bus_t, destroy, void, bus_t *bus_create() { private_bus_t *this; + debug_t group; INIT(this, .public = { .add_listener = _add_listener, .remove_listener = _remove_listener, - .listen = _listen_, + .add_logger = _add_logger, + .remove_logger = _remove_logger, .set_sa = _set_sa, .get_sa = _get_sa, .log = _log_, @@ -727,6 +797,7 @@ bus_t *bus_create() .child_keys = _child_keys, .ike_updown = _ike_updown, .ike_rekey = _ike_rekey, + .ike_reestablish = _ike_reestablish, .child_updown = _child_updown, .child_rekey = _child_rekey, .authorize = _authorize, @@ -735,9 +806,16 @@ bus_t *bus_create() }, .listeners = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), + .log_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .thread_sa = thread_value_create(NULL), ); + for (group = 0; group <= DBG_MAX; group++) + { + this->loggers[group] = linked_list_create(); + this->max_level[group] = LEVEL_SILENT; + } + return &this->public; } diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h index 69060d383..aba8acdbd 100644 --- a/src/libcharon/bus/bus.h +++ b/src/libcharon/bus/bus.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -31,6 +32,7 @@ typedef struct bus_t bus_t; #include #include #include +#include #include /* undefine the definitions from libstrongswan */ @@ -109,6 +111,8 @@ enum narrow_hook_t { NARROW_INITIATOR_PRE_AUTH, /** invoked as responder during exchange, peer is authenticated */ NARROW_RESPONDER, + /** invoked as responder after exchange, peer is authenticated */ + NARROW_RESPONDER_POST, /** invoked as initiator after exchange, follows a INITIATOR_PRE_NOAUTH */ NARROW_INITIATOR_POST_NOAUTH, /** invoked as initiator after exchange, follows a INITIATOR_PRE_AUTH */ @@ -118,8 +122,7 @@ enum narrow_hook_t { /** * The bus receives events and sends them to all registered listeners. * - * Any events sent to are delivered to all registered listeners. Threads - * may wait actively to events using the blocking listen() call. + * Loggers are handled separately. */ struct bus_t { @@ -142,26 +145,37 @@ struct bus_t { void (*remove_listener) (bus_t *this, listener_t *listener); /** - * Register a listener and block the calling thread. + * Register a logger with the bus. * - * This call registers a listener and blocks the calling thread until - * its listeners function returns FALSE. This allows to wait for certain - * events. The associated job is executed after the listener has been - * registered: This allows to listen on events we initiate with the job, - * without missing any events to job may fire. + * The logger is passive; the thread which emitted the event + * processes the logger routine. This routine may be called concurrently + * by multiple threads. Recursive calls are not prevented, so logger that + * may cause recursive calls are responsible to avoid infinite loops. * - * @param listener listener to register - * @param job job to execute asynchronously when registered, or NULL - * @param timeout max timeout in ms to listen for events, 0 to disable - * @return TRUE if timed out + * During registration get_level() is called for all log groups and the + * logger is registered to receive log messages for groups for which + * the requested log level is > LEVEL_SILENT and whose level is lower + * or equal than the requested level. + * + * To update the registered log levels call add_logger again with the + * same logger and return the new levels from get_level(). + * + * @param logger logger to register. */ - bool (*listen)(bus_t *this, listener_t *listener, job_t *job, u_int timeout); + void (*add_logger) (bus_t *this, logger_t *logger); + + /** + * Unregister a logger from the bus. + * + * @param logger logger to unregister. + */ + void (*remove_logger) (bus_t *this, logger_t *logger); /** * Set the IKE_SA the calling thread is using. * - * To associate an received log message to an IKE_SA without passing it as - * parameter each time, the thread registers the currenlty used IKE_SA + * To associate a received log message with an IKE_SA without passing it as + * parameter each time, the thread registers the currently used IKE_SA * during check-out. Before check-in, the thread unregisters the IKE_SA. * This IKE_SA is stored per-thread, so each thread has its own IKE_SA * registered. @@ -183,9 +197,8 @@ struct bus_t { /** * Send a log message to the bus. * - * The signal specifies the type of the event occurred. The format string - * specifies an additional informational or error message with a - * printf() like variable argument list. + * The format string specifies an additional informational or error + * message with a printf() like variable argument list. * Use the DBG() macros. * * @param group debugging group @@ -198,7 +211,7 @@ struct bus_t { /** * Send a log message to the bus using va_list arguments. * - * Same as bus_t.signal(), but uses va_list argument list. + * Same as bus_t.log(), but uses va_list argument list. * * @param group kind of the signal (up, down, rekeyed, ...) * @param level verbosity level of the signal @@ -212,7 +225,7 @@ struct bus_t { * Raise an alert over the bus. * * @param alert kind of alert - * @param ... alert specific attributes + * @param ... alert specific arguments */ void (*alert)(bus_t *this, alert_t alert, ...); @@ -235,10 +248,14 @@ struct bus_t { /** * Message send/receive hook. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param message message to send/receive * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not */ - void (*message)(bus_t *this, message_t *message, bool incoming); + void (*message)(bus_t *this, message_t *message, bool incoming, bool plain); /** * IKE_SA authorization hook. @@ -264,12 +281,16 @@ struct bus_t { * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) */ void (*ike_keys)(bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); + /** * CHILD_SA keymat hook. * @@ -298,6 +319,14 @@ struct bus_t { */ void (*ike_rekey)(bus_t *this, ike_sa_t *old, ike_sa_t *new); + /** + * IKE_SA reestablishing hook. + * + * @param old reestablished and obsolete IKE_SA + * @param new new IKE_SA replacing old + */ + void (*ike_reestablish)(bus_t *this, ike_sa_t *old, ike_sa_t *new); + /** * CHILD_SA up/down hook. * diff --git a/src/libcharon/bus/listeners/file_logger.c b/src/libcharon/bus/listeners/file_logger.c index 36d18619a..9c8458eb5 100644 --- a/src/libcharon/bus/listeners/file_logger.c +++ b/src/libcharon/bus/listeners/file_logger.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,6 +20,7 @@ #include "file_logger.h" +#include typedef struct private_file_logger_t private_file_logger_t; @@ -51,73 +53,80 @@ struct private_file_logger_t { * Print the name/# of the IKE_SA? */ bool ike_name; + + /** + * Mutex to ensure multi-line log messages are not torn apart + */ + mutex_t *mutex; }; -METHOD(listener_t, log_, bool, - private_file_logger_t *this, debug_t group, level_t level, int thread, - ike_sa_t* ike_sa, char *format, va_list args) +METHOD(logger_t, log_, void, + private_file_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *message) { - if (level <= this->levels[group]) - { - char buffer[8192], timestr[128], namestr[128] = ""; - char *current = buffer, *next; - struct tm tm; - time_t t; + char timestr[128], namestr[128] = ""; + const char *current = message, *next; + struct tm tm; + time_t t; - if (this->time_format) + if (this->time_format) + { + t = time(NULL); + localtime_r(&t, &tm); + strftime(timestr, sizeof(timestr), this->time_format, &tm); + } + if (this->ike_name && ike_sa) + { + if (ike_sa->get_peer_cfg(ike_sa)) { - t = time(NULL); - localtime_r(&t, &tm); - strftime(timestr, sizeof(timestr), this->time_format, &tm); + snprintf(namestr, sizeof(namestr), " <%s|%d>", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); } - if (this->ike_name && ike_sa) + else { - if (ike_sa->get_peer_cfg(ike_sa)) - { - snprintf(namestr, sizeof(namestr), " <%s|%d>", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - } - else - { - snprintf(namestr, sizeof(namestr), " <%d>", - ike_sa->get_unique_id(ike_sa)); - } + snprintf(namestr, sizeof(namestr), " <%d>", + ike_sa->get_unique_id(ike_sa)); + } + } + else + { + namestr[0] = '\0'; + } + + /* prepend a prefix in front of every line */ + this->mutex->lock(this->mutex); + while (TRUE) + { + next = strchr(current, '\n'); + if (this->time_format) + { + fprintf(this->out, "%s %.2d[%N]%s ", + timestr, thread, debug_names, group, namestr); } else { - namestr[0] = '\0'; + fprintf(this->out, "%.2d[%N]%s ", + thread, debug_names, group, namestr); } - - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), format, args); - - /* prepend a prefix in front of every line */ - while (current) + if (next == NULL) { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - if (this->time_format) - { - fprintf(this->out, "%s %.2d[%N]%s %s\n", - timestr, thread, debug_names, group, namestr, current); - } - else - { - fprintf(this->out, "%.2d[%N]%s %s\n", - thread, debug_names, group, namestr, current); - } - current = next; + fprintf(this->out, "%s\n", current); + break; } + fprintf(this->out, "%.*s\n", (int)(next - current), current); + current = next + 1; } - /* always stay registered */ - return TRUE; + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_file_logger_t *this, debug_t group) +{ + return this->levels[group]; } METHOD(file_logger_t, set_level, void, - private_file_logger_t *this, debug_t group, level_t level) + private_file_logger_t *this, debug_t group, level_t level) { if (group < DBG_ANY) { @@ -133,12 +142,13 @@ METHOD(file_logger_t, set_level, void, } METHOD(file_logger_t, destroy, void, - private_file_logger_t *this) + private_file_logger_t *this) { if (this->out != stdout && this->out != stderr) { fclose(this->out); } + this->mutex->destroy(this->mutex); free(this); } @@ -151,8 +161,9 @@ file_logger_t *file_logger_create(FILE *out, char *time_format, bool ike_name) INIT(this, .public = { - .listener = { + .logger = { .log = _log_, + .get_level = _get_level, }, .set_level = _set_level, .destroy = _destroy, @@ -160,6 +171,7 @@ file_logger_t *file_logger_create(FILE *out, char *time_format, bool ike_name) .out = out, .time_format = time_format, .ike_name = ike_name, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); set_level(this, DBG_ANY, LEVEL_SILENT); diff --git a/src/libcharon/bus/listeners/file_logger.h b/src/libcharon/bus/listeners/file_logger.h index d02f1701d..85a2690a2 100644 --- a/src/libcharon/bus/listeners/file_logger.h +++ b/src/libcharon/bus/listeners/file_logger.h @@ -21,7 +21,7 @@ #ifndef FILE_LOGGER_H_ #define FILE_LOGGER_H_ -#include +#include typedef struct file_logger_t file_logger_t; @@ -31,9 +31,9 @@ typedef struct file_logger_t file_logger_t; struct file_logger_t { /** - * Implements the listener_t interface. + * Implements the logger_t interface. */ - listener_t listener; + logger_t logger; /** * Set the loglevel for a debug group. diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h index 21caed064..782289302 100644 --- a/src/libcharon/bus/listeners/listener.h +++ b/src/libcharon/bus/listeners/listener.h @@ -30,25 +30,6 @@ typedef struct listener_t listener_t; */ struct listener_t { - /** - * Log a debugging message. - * - * The implementing signal function returns TRUE to stay registered - * to the bus, or FALSE to unregister itself. - * Calling bus_t.log() inside of a registered listener is possible, - * but the bus does not invoke listeners recursively. - * - * @param group kind of the signal (up, down, rekeyed, ...) - * @param level verbosity level of the signal - * @param thread ID of the thread raised this signal - * @param ike_sa IKE_SA associated to the event - * @param format printf() style format string - * @param args vprintf() style va_list argument list - * @return TRUE to stay registered, FALSE to unregister - */ - bool (*log)(listener_t *this, debug_t group, level_t level, int thread, - ike_sa_t *ike_sa, char* format, va_list args); - /** * Hook called if a critical alert is risen. * @@ -84,26 +65,33 @@ struct listener_t { /** * Hook called for received/sent messages of an IKE_SA. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param ike_sa IKE_SA sending/receiving a message * @param message message object * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not * @return TRUE to stay registered, FALSE to unregister */ bool (*message)(listener_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming); + bool incoming, bool plain); /** * Hook called with IKE_SA key material. * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) * @return TRUE to stay registered, FALSE to unregister */ bool (*ike_keys)(listener_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); /** * Hook called with CHILD_SA key material. @@ -138,6 +126,18 @@ struct listener_t { */ bool (*ike_rekey)(listener_t *this, ike_sa_t *old, ike_sa_t *new); + /** + * Hook called when an initiator reestablishes an IKE_SA. + * + * This is invoked right before the new IKE_SA is checked in after + * initiating it. It is not invoked on the responder. + * + * @param old IKE_SA getting reestablished (is destroyed) + * @param new new IKE_SA replacing old (gets established) + * @return TRUE to stay registered, FALSE to unregister + */ + bool (*ike_reestablish)(listener_t *this, ike_sa_t *old, ike_sa_t *new); + /** * Hook called when a CHILD_SA gets up or down. * diff --git a/src/libcharon/bus/listeners/logger.h b/src/libcharon/bus/listeners/logger.h new file mode 100644 index 000000000..3b99e7dc1 --- /dev/null +++ b/src/libcharon/bus/listeners/logger.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup logger logger + * @{ @ingroup listeners + */ + +#ifndef LOGGER_H_ +#define LOGGER_H_ + +typedef struct logger_t logger_t; + +#include + +/** + * Logger interface, listens for log events on the bus. + */ +struct logger_t { + + /** + * Log a debugging message. + * + * @note Calls to bus_t.log() are handled separately from calls to + * other functions. This callback may be called concurrently by + * multiple threads. Also recursive calls are not prevented, loggers that + * may cause recursive log messages are responsible to avoid infinite loops. + * + * @param group kind of the signal (up, down, rekeyed, ...) + * @param level verbosity level of the signal + * @param thread ID of the thread raised this signal + * @param ike_sa IKE_SA associated to the event + * @param message log message + */ + void (*log)(logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t *ike_sa, const char *message); + + /** + * Get the desired log level for a debug group. This is called during + * registration. + * + * If the desired log levels have changed, re-register the logger with + * the bus. + * + * @param group debug group + * @return max level to log (0..4) or -1 for none (see debug.h) + */ + level_t (*get_level)(logger_t *this, debug_t group); +}; + +#endif /** LOGGER_H_ @}*/ diff --git a/src/libcharon/bus/listeners/sys_logger.c b/src/libcharon/bus/listeners/sys_logger.c index c29c9f2e4..53fdefe89 100644 --- a/src/libcharon/bus/listeners/sys_logger.c +++ b/src/libcharon/bus/listeners/sys_logger.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -19,6 +20,7 @@ #include "sys_logger.h" +#include typedef struct private_sys_logger_t private_sys_logger_t; @@ -46,55 +48,63 @@ struct private_sys_logger_t { * Print the name/# of the IKE_SA? */ bool ike_name; + + /** + * Mutex to ensure multi-line log messages are not torn apart + */ + mutex_t *mutex; }; -METHOD(listener_t, log_, bool, - private_sys_logger_t *this, debug_t group, level_t level, int thread, - ike_sa_t* ike_sa, char *format, va_list args) +METHOD(logger_t, log_, void, + private_sys_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t* ike_sa, const char *message) { - if (level <= this->levels[group]) - { - char buffer[8192], groupstr[4], namestr[128] = ""; - char *current = buffer, *next; + char groupstr[4], namestr[128] = ""; + const char *current = message, *next; - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), format, args); - /* cache group name */ - snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group); + /* cache group name and optional name string */ + snprintf(groupstr, sizeof(groupstr), "%N", debug_names, group); - if (this->ike_name && ike_sa) + if (this->ike_name && ike_sa) + { + if (ike_sa->get_peer_cfg(ike_sa)) + { + snprintf(namestr, sizeof(namestr), " <%s|%d>", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + } + else { - if (ike_sa->get_peer_cfg(ike_sa)) - { - snprintf(namestr, sizeof(namestr), " <%s|%d>", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - } - else - { - snprintf(namestr, sizeof(namestr), " <%d>", - ike_sa->get_unique_id(ike_sa)); - } + snprintf(namestr, sizeof(namestr), " <%d>", + ike_sa->get_unique_id(ike_sa)); } + } - /* do a syslog with every line */ - while (current) + /* do a syslog for every line */ + this->mutex->lock(this->mutex); + while (TRUE) + { + next = strchr(current, '\n'); + if (next == NULL) { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - syslog(this->facility|LOG_INFO, "%.2d[%s]%s %s\n", + syslog(this->facility | LOG_INFO, "%.2d[%s]%s %s\n", thread, groupstr, namestr, current); - current = next; + break; } + syslog(this->facility | LOG_INFO, "%.2d[%s]%s %.*s\n", + thread, groupstr, namestr, (int)(next - current), current); + current = next + 1; } - /* always stay registered */ - return TRUE; + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_sys_logger_t *this, debug_t group) +{ + return this->levels[group]; } METHOD(sys_logger_t, set_level, void, - private_sys_logger_t *this, debug_t group, level_t level) + private_sys_logger_t *this, debug_t group, level_t level) { if (group < DBG_ANY) { @@ -110,9 +120,10 @@ METHOD(sys_logger_t, set_level, void, } METHOD(sys_logger_t, destroy, void, - private_sys_logger_t *this) + private_sys_logger_t *this) { closelog(); + this->mutex->destroy(this->mutex); free(this); } @@ -125,14 +136,16 @@ sys_logger_t *sys_logger_create(int facility, bool ike_name) INIT(this, .public = { - .listener = { + .logger = { .log = _log_, + .get_level = _get_level, }, .set_level = _set_level, .destroy = _destroy, }, .facility = facility, .ike_name = ike_name, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); set_level(this, DBG_ANY, LEVEL_SILENT); diff --git a/src/libcharon/bus/listeners/sys_logger.h b/src/libcharon/bus/listeners/sys_logger.h index d83715a6a..fcb6655ca 100644 --- a/src/libcharon/bus/listeners/sys_logger.h +++ b/src/libcharon/bus/listeners/sys_logger.h @@ -21,7 +21,7 @@ #ifndef SYS_LOGGER_H_ #define SYS_LOGGER_H_ -#include +#include typedef struct sys_logger_t sys_logger_t; @@ -31,9 +31,9 @@ typedef struct sys_logger_t sys_logger_t; struct sys_logger_t { /** - * Implements the listener_t interface. + * Implements the logger_t interface. */ - listener_t listener; + logger_t logger; /** * Set the loglevel for a debug group. diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index a93457ea4..09e123e67 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -78,12 +78,14 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data) static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { host_t *me_cand, *other_cand; + char *my_addr, *other_addr; + bool my_allow_any, other_allow_any; ike_cfg_match_t match = MATCH_NONE; if (me) { - me_cand = host_create_from_dns(cand->get_my_addr(cand), - me->get_family(me), 0); + my_addr = cand->get_my_addr(cand, &my_allow_any); + me_cand = host_create_from_dns(my_addr, me->get_family(me), 0); if (!me_cand) { return MATCH_NONE; @@ -92,7 +94,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { match += MATCH_ME; } - else if (me_cand->is_anyaddr(me_cand)) + else if (my_allow_any || me_cand->is_anyaddr(me_cand)) { match += MATCH_ANY; } @@ -110,8 +112,8 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) if (other) { - other_cand = host_create_from_dns(cand->get_other_addr(cand), - other->get_family(other), 0); + other_addr = cand->get_other_addr(cand, &other_allow_any); + other_cand = host_create_from_dns(other_addr, other->get_family(other), 0); if (!other_cand) { return MATCH_NONE; @@ -120,7 +122,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other) { match += MATCH_OTHER; } - else if (other_cand->is_anyaddr(other_cand)) + else if (other_allow_any || other_cand->is_anyaddr(other_cand)) { match += MATCH_ANY; } @@ -142,14 +144,17 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, private_backend_manager_t *this, host_t *me, host_t *other) { ike_cfg_t *current, *found = NULL; + char *my_addr, *other_addr; + bool my_allow_any, other_allow_any; enumerator_t *enumerator; ike_cfg_match_t match, best = MATCH_ANY; ike_data_t *data; - data = malloc_thing(ike_data_t); - data->this = this; - data->me = me; - data->other = other; + INIT(data, + .this = this, + .me = me, + .other = other, + ); DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other); @@ -160,12 +165,14 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, while (enumerator->enumerate(enumerator, (void**)¤t)) { match = get_ike_match(current, me, other); - + DBG3(DBG_CFG, "ike config match: %d (%H %H)", match, me, other); if (match) { - DBG2(DBG_CFG, " candidate: %s...%s, prio %d", - current->get_my_addr(current), - current->get_other_addr(current), match); + my_addr = current->get_my_addr(current, &my_allow_any); + other_addr = current->get_other_addr(current, &other_allow_any); + DBG2(DBG_CFG, " candidate: %s%s...%s%s, prio %d", + my_allow_any ? "%":"", my_addr, + other_allow_any ? "%":"", other_addr, match); if (match > best) { DESTROY_IF(found); @@ -179,8 +186,11 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, this->lock->unlock(this->lock); if (found) { - DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d", - found->get_my_addr(found), found->get_other_addr(found), best); + my_addr = found->get_my_addr(found, &my_allow_any); + other_addr = found->get_other_addr(found, &other_allow_any); + DBG2(DBG_CFG, "found matching ike config: %s%s...%s%s with prio %d", + my_allow_any ? "%":"", my_addr, + other_allow_any ? "%":"", other_addr, best); } return found; } @@ -195,9 +205,13 @@ static id_match_t get_peer_match(identification_t *id, auth_cfg_t *auth; identification_t *candidate; id_match_t match = ID_MATCH_NONE; + char *where = local ? "local" : "remote"; + chunk_t data; if (!id) { + DBG3(DBG_CFG, "peer config match %s: %d (%N)", + where, ID_MATCH_ANY, id_type_names, ID_ANY); return ID_MATCH_ANY; } @@ -221,9 +235,29 @@ static id_match_t get_peer_match(identification_t *id, } } enumerator->destroy(enumerator); + + data = id->get_encoding(id); + DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)", + where, match, id_type_names, id->get_type(id), &data); return match; } +/** + * Get match quality of IKE version + */ +static int get_version_match(ike_version_t cfg, ike_version_t req) +{ + if (req == IKE_ANY || cfg == IKE_ANY) + { + return 1; + } + if (req == cfg) + { + return 2; + } + return 0; +} + /** * data to pass nested peer enumerator */ @@ -317,17 +351,18 @@ static void insert_sorted(match_entry_t *entry, linked_list_t *list, METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, private_backend_manager_t *this, host_t *me, host_t *other, - identification_t *my_id, identification_t *other_id) + identification_t *my_id, identification_t *other_id, ike_version_t version) { enumerator_t *enumerator; peer_data_t *data; peer_cfg_t *cfg; linked_list_t *configs, *helper; - data = malloc_thing(peer_data_t); - data->lock = this->lock; - data->me = my_id; - data->other = other_id; + INIT(data, + .lock = this->lock, + .me = my_id, + .other = other_id, + ); /* create a sorted list with all matches */ this->lock->read_lock(this->lock); @@ -340,9 +375,6 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, return enumerator; } - DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", - me, my_id, other, other_id); - configs = linked_list_create(); /* only once allocated helper list for sorting */ helper = linked_list_create(); @@ -350,29 +382,26 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, { id_match_t match_peer_me, match_peer_other; ike_cfg_match_t match_ike; + int match_version; match_entry_t *entry; - chunk_t data; match_peer_me = get_peer_match(my_id, cfg, TRUE); - data = my_id->get_encoding(my_id); - DBG3(DBG_CFG, "match_peer_me: %d (%N -> %#B)", match_peer_me, - id_type_names, my_id->get_type(my_id), &data); match_peer_other = get_peer_match(other_id, cfg, FALSE); - data = other_id->get_encoding(other_id); - DBG3(DBG_CFG, "match_peer_other: %d (%N -> %#B)", match_peer_other, - id_type_names, other_id->get_type(other_id), &data); match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other); - DBG3(DBG_CFG, "match_ike: %d (%H %H)", match_ike, me, other); + match_version = get_version_match(cfg->get_ike_version(cfg), version); + DBG3(DBG_CFG, "ike config match: %d (%H %H)", match_ike, me, other); - if (match_peer_me && match_peer_other && match_ike) + if (match_peer_me && match_peer_other && match_ike && match_version) { - DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)", - cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike); - - entry = malloc_thing(match_entry_t); - entry->match_peer = match_peer_me + match_peer_other; - entry->match_ike = match_ike; - entry->cfg = cfg->get_ref(cfg); + DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d/%d " + "(me/other/ike/version)", cfg->get_name(cfg), + match_peer_me, match_peer_other, match_ike, match_version); + + INIT(entry, + .match_peer = match_peer_me + match_peer_other, + .match_ike = match_ike, + .cfg = cfg->get_ref(cfg), + ); insert_sorted(entry, configs, helper); } } diff --git a/src/libcharon/config/backend_manager.h b/src/libcharon/config/backend_manager.h index 5b394f791..de263365b 100644 --- a/src/libcharon/config/backend_manager.h +++ b/src/libcharon/config/backend_manager.h @@ -56,6 +56,7 @@ struct backend_manager_t { * * @param my_host address of own host * @param other_host address of remote host + * @param version IKE version to get a config for * @return matching ike_config, or NULL if none found */ ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this, @@ -79,11 +80,12 @@ struct backend_manager_t { * @param other remote address * @param my_id IDr in first authentication round * @param other_id IDi in first authentication round + * @param version IKE version to get a config for * @return enumerator over peer_cfg_t */ enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this, host_t *me, host_t *other, identification_t *my_id, - identification_t *other_id); + identification_t *other_id, ike_version_t version); /** * Register a backend on the manager. * diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c index 74949be3c..b675c908f 100644 --- a/src/libcharon/config/child_cfg.c +++ b/src/libcharon/config/child_cfg.c @@ -171,6 +171,8 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*, } enumerator->destroy(enumerator); + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + return proposals; } @@ -235,12 +237,16 @@ METHOD(child_cfg_t, add_traffic_selector, void, } METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, - private_child_cfg_t *this, bool local, linked_list_t *supplied, host_t *host) + private_child_cfg_t *this, bool local, linked_list_t *supplied, + linked_list_t *hosts) { enumerator_t *e1, *e2; traffic_selector_t *ts1, *ts2, *selected; - linked_list_t *result = linked_list_create(); + linked_list_t *result, *derived; + host_t *host; + result = linked_list_create(); + derived = linked_list_create(); if (local) { e1 = this->my_ts->create_enumerator(this->my_ts); @@ -249,42 +255,46 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, { e1 = this->other_ts->create_enumerator(this->other_ts); } - - /* no list supplied, just fetch the stored traffic selectors */ - if (supplied == NULL) + /* In a first step, replace "dynamic" TS with the host list */ + while (e1->enumerate(e1, &ts1)) { - DBG2(DBG_CFG, "proposing traffic selectors for %s:", - local ? "us" : "other"); - while (e1->enumerate(e1, &ts1)) + if (hosts && hosts->get_count(hosts) && + ts1->is_dynamic(ts1)) { - /* we make a copy of the TS, this allows us to update dynamic TS' */ - selected = ts1->clone(ts1); - if (host) + e2 = hosts->create_enumerator(hosts); + while (e2->enumerate(e2, &host)) { - selected->set_address(selected, host); + ts2 = ts1->clone(ts1); + ts2->set_address(ts2, host); + derived->insert_last(derived, ts2); } - DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1); - result->insert_last(result, selected); + e2->destroy(e2); + } + else + { + derived->insert_last(derived, ts1->clone(ts1)); + } + } + e1->destroy(e1); + + DBG2(DBG_CFG, "%s traffic selectors for %s:", + supplied ? "selecting" : "proposing", local ? "us" : "other"); + if (supplied == NULL) + { + while (derived->remove_first(derived, (void**)&ts1) == SUCCESS) + { + DBG2(DBG_CFG, " %R", ts1); + result->insert_last(result, ts1); } - e1->destroy(e1); } else { - DBG2(DBG_CFG, "selecting traffic selectors for %s:", - local ? "us" : "other"); - e2 = supplied->create_enumerator(supplied); - /* iterate over all stored selectors */ - while (e1->enumerate(e1, &ts1)) + e1 = supplied->create_enumerator(supplied); + /* enumerate all configured/derived selectors */ + while (derived->remove_first(derived, (void**)&ts1) == SUCCESS) { - /* we make a copy of the TS, as we have to update dynamic TS' */ - ts1 = ts1->clone(ts1); - if (host) - { - ts1->set_address(ts1, host); - } - - /* iterate over all supplied traffic selectors */ - while (e2->enumerate(e2, &ts2)) + /* enumerate all supplied traffic selectors */ + while (e1->enumerate(e1, &ts2)) { selected = ts1->get_subset(ts1, ts2); if (selected) @@ -299,13 +309,12 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, ts1, ts2); } } - e2->destroy(e2); - e2 = supplied->create_enumerator(supplied); + supplied->reset_enumerator(supplied, e1); ts1->destroy(ts1); } e1->destroy(e1); - e2->destroy(e2); } + derived->destroy(derived); /* remove any redundant traffic selectors in the list */ e1 = result->create_enumerator(result); @@ -320,16 +329,14 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*, { result->remove_at(result, e2); ts2->destroy(ts2); - e1->destroy(e1); - e1 = result->create_enumerator(result); + result->reset_enumerator(result, e1); break; } if (ts1->is_contained_in(ts1, ts2)) { result->remove_at(result, e1); ts1->destroy(ts1); - e2->destroy(e2); - e2 = result->create_enumerator(result); + result->reset_enumerator(result, e2); break; } } diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h index 370ff9d58..6e8829a47 100644 --- a/src/libcharon/config/child_cfg.h +++ b/src/libcharon/config/child_cfg.h @@ -129,12 +129,12 @@ struct child_cfg_t { * * @param local TRUE for TS on local side, FALSE for remote * @param supplied list with TS to select from, or NULL - * @param host address to use for narrowing "dynamic" TS', or NULL + * @param hosts addresses to use for narrowing "dynamic" TS', host_t * @return list containing the traffic selectors */ linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local, linked_list_t *supplied, - host_t *host); + linked_list_t *hosts); /** * Get the updown script to run for the CHILD_SA. * diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c index 342b9ddbe..acf4b6141 100644 --- a/src/libcharon/config/ike_cfg.c +++ b/src/libcharon/config/ike_cfg.c @@ -48,6 +48,16 @@ struct private_ike_cfg_t { */ char *other; + /** + * Allow override of local address + */ + bool my_allow_any; + + /** + * Allow override of remote address + */ + bool other_allow_any; + /** * our source port */ @@ -87,14 +97,22 @@ METHOD(ike_cfg_t, force_encap_, bool, } METHOD(ike_cfg_t, get_my_addr, char*, - private_ike_cfg_t *this) + private_ike_cfg_t *this, bool *allow_any) { + if (allow_any) + { + *allow_any = this->my_allow_any; + } return this->me; } METHOD(ike_cfg_t, get_other_addr, char*, - private_ike_cfg_t *this) + private_ike_cfg_t *this, bool *allow_any) { + if (allow_any) + { + *allow_any = this->other_allow_any; + } return this->other; } @@ -132,6 +150,8 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*, } enumerator->destroy(enumerator); + DBG2(DBG_CFG, "configured proposals: %#P", proposals); + return proposals; } @@ -260,7 +280,8 @@ METHOD(ike_cfg_t, destroy, void, * Described in header. */ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, - char *me, u_int16_t my_port, char *other, u_int16_t other_port) + char *me, bool my_allow_any, u_int16_t my_port, + char *other, bool other_allow_any, u_int16_t other_port) { private_ike_cfg_t *this; @@ -285,6 +306,8 @@ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, .force_encap = force_encap, .me = strdup(me), .other = strdup(other), + .my_allow_any = my_allow_any, + .other_allow_any = other_allow_any, .my_port = my_port, .other_port = other_port, .proposals = linked_list_create(), diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h index f1edde255..691d223a3 100644 --- a/src/libcharon/config/ike_cfg.h +++ b/src/libcharon/config/ike_cfg.h @@ -41,28 +41,30 @@ struct ike_cfg_t { /** * Get own address. * - * @return string of address/DNS name + * @param allow_any allow any address to match + * @return string of address/DNS name */ - char* (*get_my_addr) (ike_cfg_t *this); + char* (*get_my_addr) (ike_cfg_t *this, bool *allow_any); /** - * Get peers address. + * Get peer's address. * - * @return string of address/DNS name + * @param allow_any allow any address to match + * @return string of address/DNS name */ - char* (*get_other_addr) (ike_cfg_t *this); + char* (*get_other_addr) (ike_cfg_t *this, bool *allow_any); /** * Get the port to use as our source port. * - * @return source address port, host order + * @return source address port, host order */ u_int16_t (*get_my_port)(ike_cfg_t *this); /** * Get the port to use as destination port. * - * @return destination address, host order + * @return destination address, host order */ u_int16_t (*get_other_port)(ike_cfg_t *this); @@ -72,7 +74,7 @@ struct ike_cfg_t { * The first added proposal has the highest priority, the last * added the lowest. * - * @param proposal proposal to add + * @param proposal proposal to add */ void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal); @@ -81,7 +83,7 @@ struct ike_cfg_t { * * Returned list and its proposals must be destroyed after use. * - * @return list containing all the proposals + * @return list containing all the proposals */ linked_list_t* (*get_proposals) (ike_cfg_t *this); @@ -90,9 +92,9 @@ struct ike_cfg_t { * * Returned proposal must be destroyed after use. * - * @param proposals list of proposals to select from - * @param private accept algorithms from a private range - * @return selected proposal, or NULL if none matches. + * @param proposals list of proposals to select from + * @param private accept algorithms from a private range + * @return selected proposal, or NULL if none matches. */ proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals, bool private); @@ -100,36 +102,36 @@ struct ike_cfg_t { /** * Should we send a certificate request in IKE_SA_INIT? * - * @return certificate request sending policy + * @return certificate request sending policy */ bool (*send_certreq) (ike_cfg_t *this); /** * Enforce UDP encapsulation by faking NATD notifies? * - * @return TRUE to enfoce UDP encapsulation + * @return TRUE to enfoce UDP encapsulation */ bool (*force_encap) (ike_cfg_t *this); /** * Get the DH group to use for IKE_SA setup. * - * @return dh group to use for initialization + * @return dh group to use for initialization */ diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this); /** * Check if two IKE configs are equal. * - * @param other other to check for equality - * @return TRUE if other equal to this + * @param other other to check for equality + * @return TRUE if other equal to this */ bool (*equals)(ike_cfg_t *this, ike_cfg_t *other); /** * Increase reference count. * - * @return reference to this + * @return reference to this */ ike_cfg_t* (*get_ref) (ike_cfg_t *this); @@ -147,15 +149,18 @@ struct ike_cfg_t { * * Supplied hosts become owned by ike_cfg, the name gets cloned. * - * @param certreq TRUE to send a certificate request - * @param force_encap enforce UDP encapsulation by faking NATD notify - * @param me address/DNS name of local peer - * @param my_port IKE port to use as source, 500 uses IKEv2 port floating - * @param other address/DNS name of remote peer - * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating - * @return ike_cfg_t object. + * @param certreq TRUE to send a certificate request + * @param force_encap enforce UDP encapsulation by faking NATD notify + * @param me address/DNS name of local peer + * @param my_allow_any allow override of local address by any address + * @param my_port IKE port to use as source, 500 uses IKEv2 port floating + * @param other address/DNS name of remote peer + * @param other_allow_any allow override of remote address by any address + * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating + * @return ike_cfg_t object. */ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap, - char *me, u_int16_t my_port, char *other, u_int16_t other_port); + char *me, bool my_allow_any, u_int16_t my_port, + char *other, bool other_allow_any, u_int16_t other_port); #endif /** IKE_CFG_H_ @}*/ diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index c623cbc9b..01ca026e1 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -25,6 +25,12 @@ #include #include +ENUM(ike_version_names, IKE_ANY, IKEV2, + "IKEv1/2", + "IKEv1", + "IKEv2", +); + ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_ALWAYS_SEND", "CERT_SEND_IF_ASKED", @@ -62,7 +68,7 @@ struct private_peer_cfg_t { /** * IKE version to use for initiation */ - u_int ike_version; + ike_version_t ike_version; /** * IKE config associated to this peer config @@ -99,6 +105,11 @@ struct private_peer_cfg_t { */ bool use_mobike; + /** + * Use aggressive mode? + */ + bool aggressive; + /** * Time before starting rekeying */ @@ -125,14 +136,19 @@ struct private_peer_cfg_t { u_int32_t dpd; /** - * virtual IP to use locally + * DPD timeout intervall (used for IKEv1 only) + */ + u_int32_t dpd_timeout; + + /** + * List of virtual IPs (host_t*) to request */ - host_t *virtual_ip; + linked_list_t *vips; /** - * pool to acquire configuration attributes from + * List of pool names to use for virtual IP lookup */ - char *pool; + linked_list_t *pools; /** * local authentication configs (rulesets) @@ -169,7 +185,7 @@ METHOD(peer_cfg_t, get_name, char*, return this->name; } -METHOD(peer_cfg_t, get_ike_version, u_int, +METHOD(peer_cfg_t, get_ike_version, ike_version_t, private_peer_cfg_t *this) { return this->ike_version; @@ -240,7 +256,7 @@ METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*, * Check how good a list of TS matches a given child config */ static int get_ts_match(child_cfg_t *cfg, bool local, - linked_list_t *sup_list, host_t *host) + linked_list_t *sup_list, linked_list_t *hosts) { linked_list_t *cfg_list; enumerator_t *sup_enum, *cfg_enum; @@ -248,7 +264,7 @@ static int get_ts_match(child_cfg_t *cfg, bool local, int match = 0, round; /* fetch configured TS list, narrowing dynamic TS */ - cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host); + cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts); /* use a round counter to rate leading TS with higher priority */ round = sup_list->get_count(sup_list); @@ -281,7 +297,7 @@ static int get_ts_match(child_cfg_t *cfg, bool local, METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*, private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts, - host_t *my_host, host_t *other_host) + linked_list_t *my_hosts, linked_list_t *other_hosts) { child_cfg_t *current, *found = NULL; enumerator_t *enumerator; @@ -293,8 +309,8 @@ METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*, { int my_prio, other_prio; - my_prio = get_ts_match(current, TRUE, my_ts, my_host); - other_prio = get_ts_match(current, FALSE, other_ts, other_host); + my_prio = get_ts_match(current, TRUE, my_ts, my_hosts); + other_prio = get_ts_match(current, FALSE, other_ts, other_hosts); if (my_prio && other_prio) { @@ -336,13 +352,13 @@ METHOD(peer_cfg_t, get_keyingtries, u_int32_t, } METHOD(peer_cfg_t, get_rekey_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->rekey_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->rekey_time; } @@ -350,13 +366,13 @@ METHOD(peer_cfg_t, get_rekey_time, u_int32_t, } METHOD(peer_cfg_t, get_reauth_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->reauth_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->reauth_time; } @@ -375,22 +391,46 @@ METHOD(peer_cfg_t, use_mobike, bool, return this->use_mobike; } +METHOD(peer_cfg_t, use_aggressive, bool, + private_peer_cfg_t *this) +{ + return this->aggressive; +} + METHOD(peer_cfg_t, get_dpd, u_int32_t, private_peer_cfg_t *this) { return this->dpd; } -METHOD(peer_cfg_t, get_virtual_ip, host_t*, +METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t, private_peer_cfg_t *this) { - return this->virtual_ip; + return this->dpd_timeout; +} + +METHOD(peer_cfg_t, add_virtual_ip, void, + private_peer_cfg_t *this, host_t *vip) +{ + this->vips->insert_last(this->vips, vip); +} + +METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*, + private_peer_cfg_t *this) +{ + return this->vips->create_enumerator(this->vips); +} + +METHOD(peer_cfg_t, add_pool, void, + private_peer_cfg_t *this, char *name) +{ + this->pools->insert_last(this->pools, strdup(name)); } -METHOD(peer_cfg_t, get_pool, char*, +METHOD(peer_cfg_t, create_pool_enumerator, enumerator_t*, private_peer_cfg_t *this) { - return this->pool; + return this->pools->create_enumerator(this->pools); } METHOD(peer_cfg_t, add_auth_cfg, void, @@ -493,6 +533,10 @@ static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other) METHOD(peer_cfg_t, equals, bool, private_peer_cfg_t *this, private_peer_cfg_t *other) { + enumerator_t *e1, *e2; + host_t *vip1, *vip2; + char *pool1, *pool2; + if (this == other) { return TRUE; @@ -502,6 +546,43 @@ METHOD(peer_cfg_t, equals, bool, return FALSE; } + if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips)) + { + return FALSE; + } + e1 = create_virtual_ip_enumerator(this); + e2 = create_virtual_ip_enumerator(other); + if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2)) + { + if (!vip1->ip_equals(vip1, vip2)) + { + e1->destroy(e1); + e2->destroy(e2); + return FALSE; + } + } + e1->destroy(e1); + e2->destroy(e2); + + if (this->pools->get_count(this->pools) != + other->pools->get_count(other->pools)) + { + return FALSE; + } + e1 = create_pool_enumerator(this); + e2 = create_pool_enumerator(other); + if (e1->enumerate(e1, &pool1) && e2->enumerate(e2, &pool2)) + { + if (!streq(pool1, pool2)) + { + e1->destroy(e1); + e2->destroy(e2); + return FALSE; + } + } + e1->destroy(e1); + e2->destroy(e2); + return ( this->ike_version == other->ike_version && this->cert_policy == other->cert_policy && @@ -513,11 +594,6 @@ METHOD(peer_cfg_t, equals, bool, this->jitter_time == other->jitter_time && this->over_time == other->over_time && this->dpd == other->dpd && - (this->virtual_ip == other->virtual_ip || - (this->virtual_ip && other->virtual_ip && - this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) && - (this->pool == other->pool || - (this->pool && other->pool && streq(this->pool, other->pool))) && auth_cfg_equal(this, other) #ifdef ME && this->mediation == other->mediation && @@ -544,18 +620,18 @@ METHOD(peer_cfg_t, destroy, void, this->ike_cfg->destroy(this->ike_cfg); this->child_cfgs->destroy_offset(this->child_cfgs, offsetof(child_cfg_t, destroy)); - DESTROY_IF(this->virtual_ip); this->local_auth->destroy_offset(this->local_auth, offsetof(auth_cfg_t, destroy)); this->remote_auth->destroy_offset(this->remote_auth, offsetof(auth_cfg_t, destroy)); + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->pools->destroy_function(this->pools, free); #ifdef ME DESTROY_IF(this->mediated_by); DESTROY_IF(this->peer_id); #endif /* ME */ this->mutex->destroy(this->mutex); free(this->name); - free(this->pool); free(this); } } @@ -563,12 +639,13 @@ METHOD(peer_cfg_t, destroy, void, /* * Described in header-file */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, +peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, bool aggressive, u_int32_t dpd, + u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { @@ -599,9 +676,13 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, .get_reauth_time = _get_reauth_time, .get_over_time = _get_over_time, .use_mobike = _use_mobike, + .use_aggressive = _use_aggressive, .get_dpd = _get_dpd, - .get_virtual_ip = _get_virtual_ip, - .get_pool = _get_pool, + .get_dpd_timeout = _get_dpd_timeout, + .add_virtual_ip = _add_virtual_ip, + .create_virtual_ip_enumerator = _create_virtual_ip_enumerator, + .add_pool = _add_pool, + .create_pool_enumerator = _create_pool_enumerator, .add_auth_cfg = _add_auth_cfg, .create_auth_cfg_enumerator = _create_auth_cfg_enumerator, .equals = (void*)_equals, @@ -626,9 +707,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, .jitter_time = jitter_time, .over_time = over_time, .use_mobike = mobike, + .aggressive = aggressive, .dpd = dpd, - .virtual_ip = virtual_ip, - .pool = strdupnull(pool), + .dpd_timeout = dpd_timeout, + .vips = linked_list_create(), + .pools = linked_list_create(), .local_auth = linked_list_create(), .remote_auth = linked_list_create(), .refcount = 1, diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index f644fb547..97089e1b0 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -23,6 +23,7 @@ #ifndef PEER_CFG_H_ #define PEER_CFG_H_ +typedef enum ike_version_t ike_version_t; typedef enum cert_policy_t cert_policy_t; typedef enum unique_policy_t unique_policy_t; typedef struct peer_cfg_t peer_cfg_t; @@ -34,10 +35,25 @@ typedef struct peer_cfg_t peer_cfg_t; #include #include #include -#include -#include #include +/** + * IKE version. + */ +enum ike_version_t { + /** any version */ + IKE_ANY = 0, + /** IKE version 1 */ + IKEV1 = 1, + /** IKE version 2 */ + IKEV2 = 2, +}; + +/** + * enum strings fro ike_version_t + */ +extern enum_name_t *ike_version_names; + /** * Certificate sending policy. This is also used for certificate * requests when using this definition for the other peer. If @@ -65,11 +81,13 @@ extern enum_name_t *cert_policy_names; * Uniqueness of an IKE_SA, used to drop multiple connections with one peer. */ enum unique_policy_t { - /** do not check for client uniqueness */ + /** never check for client uniqueness */ + UNIQUE_NEVER, + /** only check for client uniqueness when receiving an INITIAL_CONTACT */ UNIQUE_NO, - /** replace unique IKE_SAs if new ones get established */ + /** replace existing IKE_SAs when new ones get established by a client */ UNIQUE_REPLACE, - /** keep existing IKE_SAs, close the new ones on connection attept */ + /** keep existing IKE_SAs, close the new ones on connection attempt */ UNIQUE_KEEP, }; @@ -130,7 +148,7 @@ struct peer_cfg_t { * * @return IKE major version */ - u_int (*get_ike_version)(peer_cfg_t *this); + ike_version_t (*get_ike_version)(peer_cfg_t *this); /** * Get the IKE config to use for initiaton. @@ -165,13 +183,13 @@ struct peer_cfg_t { * * @param my_ts TS for local side * @param other_ts TS for remote side - * @param my_host host to narrow down dynamic TS for local side - * @param other_host host to narrow down dynamic TS for remote side + * @param my_hosts hosts to narrow down dynamic TS for local side + * @param other_hosts hosts to narrow down dynamic TS for remote side * @return selected CHILD config, or NULL if no match found */ - child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, linked_list_t *my_ts, - linked_list_t *other_ts, host_t *my_host, - host_t *other_host); + child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, + linked_list_t *my_ts, linked_list_t *other_ts, + linked_list_t *my_hosts, linked_list_t *other_hosts); /** * Add an authentication config to the peer configuration. @@ -211,18 +229,20 @@ struct peer_cfg_t { u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * Get a time to start rekeying (is randomized with jitter). + * Get a time to start rekeying. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_rekey_time)(peer_cfg_t *this); + u_int32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter); /** - * Get a time to start reauthentication (is randomized with jitter). + * Get a time to start reauthentication. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start reauthentication, 0 disables it */ - u_int32_t (*get_reauth_time)(peer_cfg_t *this); + u_int32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter); /** * Get the timeout of a rekeying/reauthenticating SA. @@ -238,6 +258,13 @@ struct peer_cfg_t { */ bool (*use_mobike) (peer_cfg_t *this); + /** + * Use/Accept aggressive mode with IKEv1?. + * + * @return TRUE to use aggressive mode + */ + bool (*use_aggressive)(peer_cfg_t *this); + /** * Get the DPD check interval. * @@ -246,23 +273,41 @@ struct peer_cfg_t { u_int32_t (*get_dpd) (peer_cfg_t *this); /** - * Get a virtual IP for the local peer. + * Get the DPD timeout interval (IKEv1 only) * - * If no virtual IP should be used, NULL is returned. %any means to request - * a virtual IP using configuration payloads. A specific address is also - * used for a request and may be changed by the server. + * @return dpd_timeout in seconds + */ + u_int32_t (*get_dpd_timeout) (peer_cfg_t *this); + + /** + * Add a virtual IP to request as initiator. + * + * @param vip virtual IP to request, may be %any or %any6 + */ + void (*add_virtual_ip)(peer_cfg_t *this, host_t *vip); + + /** + * Create an enumerator over virtual IPs to request. + * + * The returned enumerator enumerates over IPs added with add_virtual_ip(). + * + * @return enumerator over host_t* + */ + enumerator_t* (*create_virtual_ip_enumerator)(peer_cfg_t *this); + + /** + * Add a pool name this configuration uses to select virtual IPs. * - * @param suggestion NULL, %any or specific - * @return virtual IP, %any or NULL + * @param name pool name to use for virtual IP lookup */ - host_t* (*get_virtual_ip) (peer_cfg_t *this); + void (*add_pool)(peer_cfg_t *this, char *name); /** - * Get the name of the pool to acquire configuration attributes from. + * Create an enumerator over pool names of this config. * - * @return pool name, NULL if none defined + * @return enumerator over char* */ - char* (*get_pool)(peer_cfg_t *this); + enumerator_t* (*create_pool_enumerator)(peer_cfg_t *this); #ifdef ME /** @@ -339,20 +384,21 @@ struct peer_cfg_t { * @param jitter_time timerange to randomly subtract from rekey/reauth time * @param over_time maximum overtime before closing a rekeying/reauth SA * @param mobike use MOBIKE (RFC4555) if peer supports it + * @param aggressive use/accept aggressive mode with IKEv1 * @param dpd DPD check interval, 0 to disable - * @param virtual_ip virtual IP for local host, or NULL - * @param pool pool name to get configuration attributes from, or NULL + * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies * @param mediation TRUE if this is a mediation connection * @param mediated_by peer_cfg_t of the mediation connection to mediate through * @param peer_id ID that identifies our peer at the mediation server * @return peer_cfg_t object */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, +peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, bool aggressive, u_int32_t dpd, + u_int32_t dpd_timeout, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c index d3c60a469..43b467f46 100644 --- a/src/libcharon/config/proposal.c +++ b/src/libcharon/config/proposal.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2006-2010 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -21,18 +21,18 @@ #include #include #include -#include + #include #include #include #include -#include -ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP, +ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP, "PROTO_NONE", "IKE", "AH", "ESP", + "IPCOMP", ); typedef struct private_proposal_t private_proposal_t; @@ -559,14 +559,15 @@ static void check_proposal(private_proposal_t *this) /** * add a algorithm identified by a string to the proposal. */ -static status_t add_string_algo(private_proposal_t *this, chunk_t alg) +static bool add_string_algo(private_proposal_t *this, const char *alg) { - const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); + const proposal_token_t *token; + token = lib->proposal->get_token(lib->proposal, alg); if (token == NULL) { - DBG1(DBG_CFG, "algorithm '%.*s' not recognized", alg.len, alg.ptr); - return FAILED; + DBG1(DBG_CFG, "algorithm '%s' not recognized", alg); + return FALSE; } add_algorithm(this, token->type, token->algorithm, token->keysize); @@ -609,13 +610,13 @@ static status_t add_string_algo(private_proposal_t *this, chunk_t alg) add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0); } } - return SUCCESS; + return TRUE; } /** * print all algorithms of a kind to buffer */ -static int print_alg(private_proposal_t *this, char **dst, size_t *len, +static int print_alg(private_proposal_t *this, printf_hook_data_t *data, u_int kind, void *names, bool *first) { enumerator_t *enumerator; @@ -627,16 +628,16 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len, { if (*first) { - written += print_in_hook(*dst, *len, "%N", names, alg); + written += print_in_hook(data, "%N", names, alg); *first = FALSE; } else { - written += print_in_hook(*dst, *len, "/%N", names, alg); + written += print_in_hook(data, "/%N", names, alg); } if (size) { - written += print_in_hook(*dst, *len, "_%u", size); + written += print_in_hook(data, "_%u", size); } } enumerator->destroy(enumerator); @@ -646,7 +647,7 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len, /** * Described in header. */ -int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { private_proposal_t *this = *((private_proposal_t**)(args[0])); @@ -657,7 +658,7 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (this == NULL) { - return print_in_hook(dst, len, "(null)"); + return print_in_hook(data, "(null)"); } if (spec->hash) @@ -667,28 +668,28 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, { /* call recursivly */ if (first) { - written += print_in_hook(dst, len, "%P", this); + written += print_in_hook(data, "%P", this); first = FALSE; } else { - written += print_in_hook(dst, len, ", %P", this); + written += print_in_hook(data, ", %P", this); } } enumerator->destroy(enumerator); return written; } - written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol); - written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM, + written = print_in_hook(data, "%N:", protocol_id_names, this->protocol); + written += print_alg(this, data, ENCRYPTION_ALGORITHM, encryption_algorithm_names, &first); - written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM, + written += print_alg(this, data, INTEGRITY_ALGORITHM, integrity_algorithm_names, &first); - written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION, + written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION, pseudo_random_function_names, &first); - written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP, + written += print_alg(this, data, DIFFIE_HELLMAN_GROUP, diffie_hellman_group_names, &first); - written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS, + written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS, extended_sequence_numbers_names, &first); return written; } @@ -840,6 +841,7 @@ static void proposal_add_supported_ike(private_proposal_t *this) case MODP_1024_BIT: case MODP_1536_BIT: case MODP_2048_BIT: + case MODP_3072_BIT: case MODP_4096_BIT: case MODP_8192_BIT: case ECP_256_BIT: @@ -899,28 +901,27 @@ proposal_t *proposal_create_default(protocol_id_t protocol) */ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs) { - private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0); - chunk_t string = {(void*)algs, strlen(algs)}; - chunk_t alg; - status_t status = SUCCESS; + private_proposal_t *this; + enumerator_t *enumerator; + bool failed = TRUE; + char *alg; - eat_whitespace(&string); - if (string.len < 1) - { - destroy(this); - return NULL; - } + this = (private_proposal_t*)proposal_create(protocol, 0); /* get all tokens, separated by '-' */ - while (extract_token(&alg, '-', &string)) - { - status |= add_string_algo(this, alg); - } - if (string.len) + enumerator = enumerator_create_token(algs, "-", " "); + while (enumerator->enumerate(enumerator, &alg)) { - status |= add_string_algo(this, string); + if (!add_string_algo(this, alg)) + { + failed = TRUE; + break; + } + failed = FALSE; } - if (status != SUCCESS) + enumerator->destroy(enumerator); + + if (failed) { destroy(this); return NULL; diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h index 8f54d7e6e..33abf006c 100644 --- a/src/libcharon/config/proposal.h +++ b/src/libcharon/config/proposal.h @@ -43,6 +43,7 @@ enum protocol_id_t { PROTO_IKE = 1, PROTO_AH = 2, PROTO_ESP = 3, + PROTO_IPCOMP = 4, /* IKEv1 only */ }; /** @@ -215,7 +216,7 @@ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs * With the #-specifier, arguments are: * linked_list_t *list containing proposal_t* */ -int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** PROPOSAL_H_ @}*/ diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index 0f247962b..77d73dba9 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011-2012 Tobias Brunner * Copyright (C) 2007-2011 Martin Willi * Copyright (C) 2011 revosec AG * Hochschule fuer Technik Rapperswil @@ -23,10 +24,13 @@ #include #include - +#include +#include +#include typedef struct private_controller_t private_controller_t; typedef struct interface_listener_t interface_listener_t; +typedef struct interface_logger_t interface_logger_t; /** * Private data of an stroke_t object. @@ -40,19 +44,18 @@ struct private_controller_t { }; /** - * helper struct to map listener callbacks to interface callbacks + * helper struct for the logger interface */ -struct interface_listener_t { - +struct interface_logger_t { /** - * public bus listener interface + * public logger interface */ - listener_t public; + logger_t public; /** - * status of the operation, return to method callers + * reference to the listener */ - status_t status; + interface_listener_t *listener; /** * interface callback (listener gets redirected to here) @@ -63,6 +66,27 @@ struct interface_listener_t { * user parameter to pass to callback */ void *param; +}; + +/** + * helper struct to map listener callbacks to interface callbacks + */ +struct interface_listener_t { + + /** + * public bus listener interface + */ + listener_t public; + + /** + * logger interface + */ + interface_logger_t logger; + + /** + * status of the operation, return to method callers + */ + status_t status; /** * child configuration, used for initiate @@ -80,14 +104,19 @@ struct interface_listener_t { ike_sa_t *ike_sa; /** - * CHILD_SA to handle + * unique ID, used for various methods */ - child_sa_t *child_sa; + u_int32_t id; /** - * unique ID, used for various methods + * semaphore to implement wait_for_listener() */ - u_int32_t id; + semaphore_t *done; + + /** + * spinlock to update the IKE_SA handle properly + */ + spinlock_t *lock; }; @@ -107,20 +136,103 @@ struct interface_job_t { * associated listener */ interface_listener_t listener; + + /** + * the job is reference counted as the thread executing a job as well as + * the thread waiting in wait_for_listener() require it but either of them + * could be done first + */ + refcount_t refcount; }; -METHOD(listener_t, listener_log, bool, - interface_listener_t *this, debug_t group, level_t level, int thread, - ike_sa_t *ike_sa, char* format, va_list args) +/** + * This function wakes a thread that is waiting in wait_for_listener(), + * either from a listener or from a job. + */ +static inline bool listener_done(interface_listener_t *listener) { - if (this->ike_sa == ike_sa) + if (listener->done) { - if (!this->callback(this->param, group, level, ike_sa, format, args)) + listener->done->post(listener->done); + } + return FALSE; +} + +/** + * thread_cleanup_t handler to unregister a listener. + */ +static void listener_unregister(interface_listener_t *listener) +{ + charon->bus->remove_listener(charon->bus, &listener->public); + charon->bus->remove_logger(charon->bus, &listener->logger.public); +} + +/** + * Registers the listener, executes the job and then waits synchronously until + * the listener is done or the timeout occurred. + * + * @note Use 'return listener_done(listener)' to properly unregister a listener + * + * @param listener listener to register + * @param job job to execute asynchronously when registered, or NULL + * @param timeout max timeout in ms to listen for events, 0 to disable + * @return TRUE if timed out + */ +static bool wait_for_listener(interface_job_t *job, u_int timeout) +{ + interface_listener_t *listener = &job->listener; + bool old, timed_out = FALSE; + + /* avoid that the job is destroyed too early */ + ref_get(&job->refcount); + + listener->done = semaphore_create(0); + + charon->bus->add_logger(charon->bus, &listener->logger.public); + charon->bus->add_listener(charon->bus, &listener->public); + lib->processor->queue_job(lib->processor, &job->public); + + thread_cleanup_push((thread_cleanup_t)listener_unregister, listener); + old = thread_cancelability(TRUE); + if (timeout) + { + timed_out = listener->done->timed_wait(listener->done, timeout); + } + else + { + listener->done->wait(listener->done); + } + thread_cancelability(old); + thread_cleanup_pop(TRUE); + return timed_out; +} + +METHOD(logger_t, listener_log, void, + interface_logger_t *this, debug_t group, level_t level, int thread, + ike_sa_t *ike_sa, const char *message) +{ + ike_sa_t *target; + + this->listener->lock->lock(this->listener->lock); + target = this->listener->ike_sa; + this->listener->lock->unlock(this->listener->lock); + + if (target == ike_sa) + { + if (!this->callback(this->param, group, level, ike_sa, message)) { - return FALSE; + this->listener->status = NEED_MORE; + listener_done(this->listener); } } - return TRUE; +} + +METHOD(logger_t, listener_get_level, level_t, + interface_logger_t *this, debug_t group) +{ + /* in order to allow callback listeners to decide what they want to log + * we request any log message, but only if we actually want logging */ + return this->callback == controller_cb_empty ? LEVEL_SILENT : LEVEL_PRIVATE; } METHOD(job_t, get_priority_medium, job_priority_t, @@ -132,7 +244,13 @@ METHOD(job_t, get_priority_medium, job_priority_t, METHOD(listener_t, ike_state_change, bool, interface_listener_t *this, ike_sa_t *ike_sa, ike_sa_state_t state) { - if (this->ike_sa == ike_sa) + ike_sa_t *target; + + this->lock->lock(this->lock); + target = this->ike_sa; + this->lock->unlock(this->lock); + + if (target == ike_sa) { switch (state) { @@ -144,7 +262,7 @@ METHOD(listener_t, ike_state_change, bool, if (peer_cfg->is_mediation(peer_cfg)) { this->status = SUCCESS; - return FALSE; + return listener_done(this); } break; } @@ -154,7 +272,7 @@ METHOD(listener_t, ike_state_change, bool, { /* proper termination */ this->status = SUCCESS; } - return FALSE; + return listener_done(this); default: break; } @@ -166,13 +284,19 @@ METHOD(listener_t, child_state_change, bool, interface_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, child_sa_state_t state) { - if (this->ike_sa == ike_sa) + ike_sa_t *target; + + this->lock->lock(this->lock); + target = this->ike_sa; + this->lock->unlock(this->lock); + + if (target == ike_sa) { switch (state) { case CHILD_INSTALLED: this->status = SUCCESS; - return FALSE; + return listener_done(this); case CHILD_DESTROYING: switch (child_sa->get_state(child_sa)) { @@ -183,7 +307,7 @@ METHOD(listener_t, child_state_change, bool, default: break; } - return FALSE; + return listener_done(this); default: break; } @@ -191,13 +315,14 @@ METHOD(listener_t, child_state_change, bool, return TRUE; } -METHOD(job_t, recheckin, void, - interface_job_t *job) +METHOD(job_t, destroy_job, void, + interface_job_t *this) { - if (job->listener.ike_sa) + if (ref_put(&this->refcount)) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, - job->listener.ike_sa); + this->listener.lock->destroy(this->listener.lock); + DESTROY_IF(this->listener.done); + free(this); } } @@ -208,7 +333,7 @@ METHOD(controller_t, create_ike_sa_enumerator, enumerator_t*, wait); } -METHOD(job_t, initiate_execute, void, +METHOD(job_t, initiate_execute, job_requeue_t, interface_job_t *job) { ike_sa_t *ike_sa; @@ -217,7 +342,18 @@ METHOD(job_t, initiate_execute, void, ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + listener->child_cfg->destroy(listener->child_cfg); + peer_cfg->destroy(peer_cfg); + listener->status = FAILED; + /* release listener */ + listener_done(listener); + return JOB_REQUEUE_NONE; + } + listener->lock->lock(listener->lock); listener->ike_sa = ike_sa; + listener->lock->unlock(listener->lock); if (ike_sa->get_peer_cfg(ike_sa) == NULL) { @@ -227,228 +363,271 @@ METHOD(job_t, initiate_execute, void, if (ike_sa->initiate(ike_sa, listener->child_cfg, 0, NULL, NULL) == SUCCESS) { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); listener->status = SUCCESS; + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } else { + listener->status = FAILED; charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - listener->status = FAILED; } + return JOB_REQUEUE_NONE; } METHOD(controller_t, initiate, status_t, private_controller_t *this, peer_cfg_t *peer_cfg, child_cfg_t *child_cfg, controller_cb_t callback, void *param, u_int timeout) { - interface_job_t job = { + interface_job_t *job; + status_t status; + + INIT(job, .listener = { .public = { - .log = _listener_log, .ike_state_change = _ike_state_change, .child_state_change = _child_state_change, }, - .callback = callback, - .param = param, + .logger = { + .public = { + .log = _listener_log, + .get_level = _listener_get_level, + }, + .callback = callback, + .param = param, + }, .status = FAILED, .child_cfg = child_cfg, .peer_cfg = peer_cfg, + .lock = spinlock_create(), }, .public = { .execute = _initiate_execute, .get_priority = _get_priority_medium, - .destroy = _recheckin, + .destroy = _destroy_job, }, - }; + .refcount = 1, + ); + job->listener.logger.listener = &job->listener; + if (callback == NULL) { - initiate_execute(&job); + initiate_execute(job); } else { - if (charon->bus->listen(charon->bus, &job.listener.public, &job.public, - timeout)) + if (wait_for_listener(job, timeout)) { - job.listener.status = OUT_OF_RES; + job->listener.status = OUT_OF_RES; } } - return job.listener.status; + status = job->listener.status; + destroy_job(job); + return status; } -METHOD(job_t, terminate_ike_execute, void, +METHOD(job_t, terminate_ike_execute, job_requeue_t, interface_job_t *job) { interface_listener_t *listener = &job->listener; - ike_sa_t *ike_sa = listener->ike_sa; + u_int32_t unique_id = listener->id; + ike_sa_t *ike_sa; - charon->bus->set_sa(charon->bus, ike_sa); + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + unique_id, FALSE); + if (!ike_sa) + { + DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id); + listener->status = NOT_FOUND; + /* release listener */ + listener_done(listener); + return JOB_REQUEUE_NONE; + } + listener->lock->lock(listener->lock); + listener->ike_sa = ike_sa; + listener->lock->unlock(listener->lock); if (ike_sa->delete(ike_sa) != DESTROY_ME) - { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - /* delete failed */ + { /* delete failed */ listener->status = FAILED; + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } else { + listener->status = SUCCESS; charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - listener->status = SUCCESS; } + return JOB_REQUEUE_NONE; } METHOD(controller_t, terminate_ike, status_t, controller_t *this, u_int32_t unique_id, controller_cb_t callback, void *param, u_int timeout) { - ike_sa_t *ike_sa; - interface_job_t job = { + interface_job_t *job; + status_t status; + + INIT(job, .listener = { .public = { - .log = _listener_log, .ike_state_change = _ike_state_change, .child_state_change = _child_state_change, }, - .callback = callback, - .param = param, + .logger = { + .public = { + .log = _listener_log, + .get_level = _listener_get_level, + }, + .callback = callback, + .param = param, + }, .status = FAILED, .id = unique_id, + .lock = spinlock_create(), }, .public = { .execute = _terminate_ike_execute, .get_priority = _get_priority_medium, - .destroy = _recheckin, + .destroy = _destroy_job, }, - }; - - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - unique_id, FALSE); - if (ike_sa == NULL) - { - DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id); - return NOT_FOUND; - } - job.listener.ike_sa = ike_sa; + .refcount = 1, + ); + job->listener.logger.listener = &job->listener; if (callback == NULL) { - terminate_ike_execute(&job); + terminate_ike_execute(job); } else { - if (charon->bus->listen(charon->bus, &job.listener.public, &job.public, - timeout)) + if (wait_for_listener(job, timeout)) { - job.listener.status = OUT_OF_RES; + job->listener.status = OUT_OF_RES; } - /* checkin of the ike_sa happened in the thread that executed the job */ - charon->bus->set_sa(charon->bus, NULL); } - return job.listener.status; + status = job->listener.status; + destroy_job(job); + return status; } -METHOD(job_t, terminate_child_execute, void, +METHOD(job_t, terminate_child_execute, job_requeue_t, interface_job_t *job) { interface_listener_t *listener = &job->listener; - ike_sa_t *ike_sa = listener->ike_sa; - child_sa_t *child_sa = listener->child_sa; + u_int32_t reqid = listener->id; + enumerator_t *enumerator; + child_sa_t *child_sa; + ike_sa_t *ike_sa; - charon->bus->set_sa(charon->bus, ike_sa); - if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)) != DESTROY_ME) + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + reqid, TRUE); + if (!ike_sa) + { + DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found", + reqid); + listener->status = NOT_FOUND; + /* release listener */ + listener_done(listener); + return JOB_REQUEUE_NONE; + } + listener->lock->lock(listener->lock); + listener->ike_sa = ike_sa; + listener->lock->unlock(listener->lock); + + enumerator = ike_sa->create_child_sa_enumerator(ike_sa); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) { + if (child_sa->get_state(child_sa) != CHILD_ROUTED && + child_sa->get_reqid(child_sa) == reqid) + { + break; + } + child_sa = NULL; + } + enumerator->destroy(enumerator); + + if (!child_sa) + { + DBG1(DBG_IKE, "unable to terminate, established " + "CHILD_SA with ID %d not found", reqid); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + listener->status = NOT_FOUND; + /* release listener */ + listener_done(listener); + return JOB_REQUEUE_NONE; + } + + if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE), FALSE) != DESTROY_ME) + { listener->status = SUCCESS; + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } else { + listener->status = FAILED; charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - listener->status = FAILED; } + return JOB_REQUEUE_NONE; } METHOD(controller_t, terminate_child, status_t, controller_t *this, u_int32_t reqid, controller_cb_t callback, void *param, u_int timeout) { - ike_sa_t *ike_sa; - child_sa_t *child_sa; - enumerator_t *enumerator; - interface_job_t job = { + interface_job_t *job; + status_t status; + + INIT(job, .listener = { .public = { - .log = _listener_log, .ike_state_change = _ike_state_change, .child_state_change = _child_state_change, }, - .callback = callback, - .param = param, + .logger = { + .public = { + .log = _listener_log, + .get_level = _listener_get_level, + }, + .callback = callback, + .param = param, + }, .status = FAILED, .id = reqid, + .lock = spinlock_create(), }, .public = { .execute = _terminate_child_execute, .get_priority = _get_priority_medium, - .destroy = _recheckin, + .destroy = _destroy_job, }, - }; - - ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, - reqid, TRUE); - if (ike_sa == NULL) - { - DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found", - reqid); - return NOT_FOUND; - } - job.listener.ike_sa = ike_sa; - - enumerator = ike_sa->create_child_sa_enumerator(ike_sa); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - if (child_sa->get_state(child_sa) != CHILD_ROUTED && - child_sa->get_reqid(child_sa) == reqid) - { - break; - } - child_sa = NULL; - } - enumerator->destroy(enumerator); - - if (child_sa == NULL) - { - DBG1(DBG_IKE, "unable to terminate, established " - "CHILD_SA with ID %d not found", reqid); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return NOT_FOUND; - } - job.listener.child_sa = child_sa; + .refcount = 1, + ); + job->listener.logger.listener = &job->listener; if (callback == NULL) { - terminate_child_execute(&job); + terminate_child_execute(job); } else { - if (charon->bus->listen(charon->bus, &job.listener.public, &job.public, - timeout)) + if (wait_for_listener(job, timeout)) { - job.listener.status = OUT_OF_RES; + job->listener.status = OUT_OF_RES; } - /* checkin of the ike_sa happened in the thread that executed the job */ - charon->bus->set_sa(charon->bus, NULL); } - return job.listener.status; + status = job->listener.status; + destroy_job(job); + return status; } /** * See header */ bool controller_cb_empty(void *param, debug_t group, level_t level, - ike_sa_t *ike_sa, char *format, va_list args) + ike_sa_t *ike_sa, const char *message) { return TRUE; } diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h index 6adaef109..222285cde 100644 --- a/src/libcharon/control/controller.h +++ b/src/libcharon/control/controller.h @@ -24,27 +24,26 @@ #include /** - * callback to log things triggered by controller. + * Callback to log things triggered by controller. * - * @param param echoed parameter supplied when function invoked + * @param param parameter supplied when controller method was called * @param group debugging group - * @param level verbosity level if log + * @param level verbosity level * @param ike_sa associated IKE_SA, if any - * @param format printf like format string - * @param args list of arguments to use for format - * @return FALSE to return from invoked function + * @param message log message + * @return FALSE to return from called controller method */ -typedef bool(*controller_cb_t)(void* param, debug_t group, level_t level, - ike_sa_t* ike_sa, char* format, va_list args); +typedef bool (*controller_cb_t)(void* param, debug_t group, level_t level, + ike_sa_t* ike_sa, const char *message); /** - * Empty callback function for controller_t functions. + * Empty callback function for controller_t methods. * * If you want to do a synchronous call, but don't need a callback, pass - * this function to the controllers methods. + * this function to the controller methods. */ bool controller_cb_empty(void *param, debug_t group, level_t level, - ike_sa_t *ike_sa, char *format, va_list args); + ike_sa_t *ike_sa, const char *message); typedef struct controller_t controller_t; @@ -75,9 +74,8 @@ struct controller_t { /** * Initiate a CHILD_SA, and if required, an IKE_SA. * - * The initiate() function is synchronous and thus blocks until the - * IKE_SA is established or failed. Because of this, the initiate() function - * contains a thread cancellation point. + * If a callback is provided the function is synchronous and thus blocks + * until the IKE_SA is established or failed. * * @param peer_cfg peer_cfg to use for IKE_SA setup * @param child_cfg child_cfg to set up CHILD_SA from @@ -97,9 +95,8 @@ struct controller_t { /** * Terminate an IKE_SA and all of its CHILD_SAs. * - * The terminate() function is synchronous and thus blocks until the - * IKE_SA is properly deleted, or the delete timed out. - * The terminate() function contains a thread cancellation point. + * If a callback is provided the function is synchronous and thus blocks + * until the IKE_SA is properly deleted, or the call timed out. * * @param unique_id unique id of the IKE_SA to terminate. * @param cb logging callback @@ -118,6 +115,9 @@ struct controller_t { /** * Terminate a CHILD_SA. * + * If a callback is provided the function is synchronous and thus blocks + * until the CHILD_SA is properly deleted, or the call timed out. + * * @param reqid reqid of the CHILD_SA to terminate * @param cb logging callback * @param param parameter to include in each call of cb @@ -138,12 +138,11 @@ struct controller_t { void (*destroy) (controller_t *this); }; - /** * Creates a controller instance. * * @return controller_t object */ -controller_t *controller_create(void); +controller_t *controller_create(); #endif /** CONTROLLER_H_ @}*/ diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index 3fb49d475..6e977efc4 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -21,22 +21,18 @@ #include #include -#ifdef CAPABILITIES -# ifdef HAVE_SYS_CAPABILITY_H -# include -# elif defined(CAPABILITIES_NATIVE) -# include -# endif /* CAPABILITIES_NATIVE */ -#endif /* CAPABILITIES */ - #include "daemon.h" #include -#include +#include #include #include #include +#ifndef CAP_NET_ADMIN +#define CAP_NET_ADMIN 12 +#endif + typedef struct private_daemon_t private_daemon_t; /** @@ -52,17 +48,6 @@ struct private_daemon_t { * Handler for kernel events */ kernel_handler_t *kernel_handler; - - /** - * capabilities to keep - */ -#ifdef CAPABILITIES_LIBCAP - cap_t caps; -#endif /* CAPABILITIES_LIBCAP */ -#ifdef CAPABILITIES_NATIVE - struct __user_cap_data_struct caps[2]; -#endif /* CAPABILITIES_NATIVE */ - }; /** @@ -109,27 +94,31 @@ static void destroy(private_daemon_t *this) { this->public.traps->flush(this->public.traps); } - DESTROY_IF(this->public.receiver); - DESTROY_IF(this->public.sender); + if (this->public.sender) + { + this->public.sender->flush(this->public.sender); + } + + /* cancel all threads and wait for their termination */ + lib->processor->cancel(lib->processor); + #ifdef ME DESTROY_IF(this->public.connect_manager); DESTROY_IF(this->public.mediation_manager); #endif /* ME */ /* make sure the cache is clear before unloading plugins */ lib->credmgr->flush_cache(lib->credmgr, CERT_ANY); - /* unload plugins to release threads */ lib->plugins->unload(lib->plugins); -#ifdef CAPABILITIES_LIBCAP - cap_free(this->caps); -#endif /* CAPABILITIES_LIBCAP */ DESTROY_IF(this->kernel_handler); DESTROY_IF(this->public.traps); DESTROY_IF(this->public.shunts); DESTROY_IF(this->public.ike_sa_manager); DESTROY_IF(this->public.controller); DESTROY_IF(this->public.eap); + DESTROY_IF(this->public.xauth); DESTROY_IF(this->public.backends); DESTROY_IF(this->public.socket); + DESTROY_IF(this->public.caps); /* rehook library logging, shutdown logging */ dbg = dbg_old; @@ -138,86 +127,63 @@ static void destroy(private_daemon_t *this) offsetof(file_logger_t, destroy)); this->public.sys_loggers->destroy_offset(this->public.sys_loggers, offsetof(sys_logger_t, destroy)); + free((void*)this->public.name); free(this); } -METHOD(daemon_t, keep_cap, void, - private_daemon_t *this, u_int cap) +METHOD(daemon_t, start, void, + private_daemon_t *this) { -#ifdef CAPABILITIES_LIBCAP - cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); - cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET); - cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET); -#endif /* CAPABILITIES_LIBCAP */ -#ifdef CAPABILITIES_NATIVE - int i = 0; - - if (cap >= 32) - { - i++; - cap -= 32; - } - this->caps[i].effective |= 1 << cap; - this->caps[i].permitted |= 1 << cap; - this->caps[i].inheritable |= 1 << cap; -#endif /* CAPABILITIES_NATIVE */ + /* start the engine, go multithreaded */ + lib->processor->set_threads(lib->processor, + lib->settings->get_int(lib->settings, "%s.threads", + DEFAULT_THREADS, charon->name)); } -METHOD(daemon_t, drop_capabilities, bool, - private_daemon_t *this) + +/** + * Initialize/deinitialize sender and receiver + */ +static bool sender_receiver_cb(void *plugin, plugin_feature_t *feature, + bool reg, private_daemon_t *this) { -#ifdef CAPABILITIES_LIBCAP - if (cap_set_proc(this->caps) != 0) + if (reg) { - return FALSE; + this->public.receiver = receiver_create(); + if (!this->public.receiver) + { + return FALSE; + } + this->public.sender = sender_create(); } -#endif /* CAPABILITIES_LIBCAP */ -#ifdef CAPABILITIES_NATIVE - struct __user_cap_header_struct header = { -#if defined(_LINUX_CAPABILITY_VERSION_3) - .version = _LINUX_CAPABILITY_VERSION_3, -#elif defined(_LINUX_CAPABILITY_VERSION_2) - .version = _LINUX_CAPABILITY_VERSION_2, -#elif defined(_LINUX_CAPABILITY_VERSION_1) - .version = _LINUX_CAPABILITY_VERSION_1, -#else - .version = _LINUX_CAPABILITY_VERSION, -#endif - }; - if (capset(&header, this->caps) != 0) + else { - return FALSE; + DESTROY_IF(this->public.receiver); + DESTROY_IF(this->public.sender); } -#endif /* CAPABILITIES_NATIVE */ return TRUE; } -METHOD(daemon_t, start, void, - private_daemon_t *this) -{ - /* start the engine, go multithreaded */ - lib->processor->set_threads(lib->processor, - lib->settings->get_int(lib->settings, "charon.threads", - DEFAULT_THREADS)); -} - METHOD(daemon_t, initialize, bool, - private_daemon_t *this) + private_daemon_t *this, char *plugins) { - DBG1(DBG_DMN, "Starting IKEv2 charon daemon (strongSwan "VERSION")"); - - if (lib->integrity) - { - DBG1(DBG_DMN, "integrity tests enabled:"); - DBG1(DBG_DMN, "lib 'libstrongswan': passed file and segment integrity tests"); - DBG1(DBG_DMN, "lib 'libhydra': passed file and segment integrity tests"); - DBG1(DBG_DMN, "lib 'libcharon': passed file and segment integrity tests"); - DBG1(DBG_DMN, "daemon 'charon': passed file integrity test"); - } + plugin_feature_t features[] = { + PLUGIN_PROVIDE(CUSTOM, "libcharon"), + PLUGIN_DEPENDS(NONCE_GEN), + PLUGIN_DEPENDS(CUSTOM, "libcharon-receiver"), + PLUGIN_DEPENDS(CUSTOM, "kernel-ipsec"), + PLUGIN_DEPENDS(CUSTOM, "kernel-net"), + PLUGIN_CALLBACK((plugin_feature_callback_t)sender_receiver_cb, this), + PLUGIN_PROVIDE(CUSTOM, "libcharon-receiver"), + PLUGIN_DEPENDS(HASHER, HASH_SHA1), + PLUGIN_DEPENDS(RNG, RNG_STRONG), + PLUGIN_DEPENDS(CUSTOM, "socket"), + }; + lib->plugins->add_static_features(lib->plugins, charon->name, features, + countof(features), TRUE); /* load plugins, further infrastructure may need it */ - if (!lib->plugins->load(lib->plugins, NULL, - lib->settings->get_str(lib->settings, "charon.load", PLUGINS))) + if (!lib->plugins->load(lib->plugins, NULL, plugins)) { return FALSE; } @@ -229,12 +195,6 @@ METHOD(daemon_t, initialize, bool, { return FALSE; } - this->public.sender = sender_create(); - this->public.receiver = receiver_create(); - if (this->public.receiver == NULL) - { - return FALSE; - } /* Queue start_action job */ lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create()); @@ -254,40 +214,32 @@ METHOD(daemon_t, initialize, bool, /** * Create the daemon. */ -private_daemon_t *daemon_create() +private_daemon_t *daemon_create(const char *name) { private_daemon_t *this; INIT(this, .public = { - .keep_cap = _keep_cap, - .drop_capabilities = _drop_capabilities, .initialize = _initialize, .start = _start, .bus = bus_create(), .file_loggers = linked_list_create(), .sys_loggers = linked_list_create(), + .name = strdup(name ?: "libcharon"), }, ); charon = &this->public; + this->public.caps = capabilities_create(); this->public.controller = controller_create(); this->public.eap = eap_manager_create(); + this->public.xauth = xauth_manager_create(); this->public.backends = backend_manager_create(); this->public.socket = socket_manager_create(); this->public.traps = trap_manager_create(); this->public.shunts = shunt_manager_create(); this->kernel_handler = kernel_handler_create(); -#ifdef CAPABILITIES -#ifdef CAPABILITIES_LIBCAP - this->caps = cap_init(); -#endif /* CAPABILITIES_LIBCAP */ - keep_cap(this, CAP_NET_ADMIN); - if (lib->leak_detective) - { - keep_cap(this, CAP_SYS_NICE); - } -#endif /* CAPABILITIES */ + this->public.caps->keep(this->public.caps, CAP_NET_ADMIN); return this; } @@ -304,9 +256,9 @@ void libcharon_deinit() /** * Described in header. */ -bool libcharon_init() +bool libcharon_init(const char *name) { - daemon_create(); + daemon_create(name); /* for uncritical pseudo random numbers */ srandom(time(NULL) + getpid()); diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h index 2e01c8d9b..b67de77b8 100644 --- a/src/libcharon/daemon.h +++ b/src/libcharon/daemon.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -55,15 +55,30 @@ * @defgroup sa sa * @ingroup libcharon * - * @defgroup authenticators authenticators + * @defgroup ikev1 ikev1 * @ingroup sa * + * @defgroup ikev2 ikev2 + * @ingroup sa + * + * @defgroup authenticators_v1 authenticators + * @ingroup ikev1 + * + * @defgroup authenticators_v2 authenticators + * @ingroup ikev2 + * * @defgroup eap eap - * @ingroup authenticators + * @ingroup sa * - * @defgroup tasks tasks + * @defgroup xauth xauth * @ingroup sa * + * @defgroup tasks_v1 tasks + * @ingroup ikev1 + * + * @defgroup tasks_v2 tasks + * @ingroup ikev2 + * * @addtogroup libcharon * @{ * @@ -148,11 +163,13 @@ typedef struct daemon_t daemon_t; #include #include #include -#include +#include +#include +#include #ifdef ME -#include -#include +#include +#include #endif /* ME */ /** @@ -161,15 +178,30 @@ typedef struct daemon_t daemon_t; #define DEFAULT_THREADS 16 /** - * UDP Port on which the daemon will listen for incoming traffic. + * Primary UDP port used by IKE. */ #define IKEV2_UDP_PORT 500 /** - * UDP Port to which the daemon will float to if NAT is detected. + * UDP port defined for use in case a NAT is detected. */ #define IKEV2_NATT_PORT 4500 +/** + * UDP port on which the daemon will listen for incoming traffic (also used as + * source port for outgoing traffic). + */ +#ifndef CHARON_UDP_PORT +#define CHARON_UDP_PORT IKEV2_UDP_PORT +#endif + +/** + * UDP port used by the daemon in case a NAT is detected. + */ +#ifndef CHARON_NATT_PORT +#define CHARON_NATT_PORT IKEV2_NATT_PORT +#endif + /** * Main class of daemon, contains some globals. */ @@ -235,6 +267,11 @@ struct daemon_t { */ eap_manager_t *eap; + /** + * XAuth manager to maintain registered XAuth methods + */ + xauth_manager_t *xauth; + #ifdef ME /** * Connect manager @@ -248,39 +285,22 @@ struct daemon_t { #endif /* ME */ /** - * User ID the daemon will user after initialization + * POSIX capability dropping */ - uid_t uid; + capabilities_t *caps; /** - * Group ID the daemon will use after initialization - */ - gid_t gid; - - /** - * Do not drop a given capability after initialization. - * - * Some plugins might need additional capabilites. They tell the daemon - * during plugin initialization which one they need, the daemon won't - * drop these. + * Name of the binary that uses the library (used for settings etc.) */ - void (*keep_cap)(daemon_t *this, u_int cap); - - /** - * Drop all capabilities of the current process. - * - * Drops all capabalities, excect those exlcuded using keep_cap(). - * This should be called after the initialization of the daemon because - * some plugins require the process to keep additional capabilities. - * - * @return TRUE if successful, FALSE otherwise - */ - bool (*drop_capabilities)(daemon_t *this); + const char *name; /** * Initialize the daemon. + * + * @param plugins list of plugins to load + * @return TRUE, if successful */ - bool (*initialize)(daemon_t *this); + bool (*initialize)(daemon_t *this, char *plugins); /** * Starts the daemon, i.e. spawns the threads of the thread pool. @@ -302,9 +322,10 @@ extern daemon_t *charon; * This function initializes the bus, listeners can be registered before * calling initialize(). * + * @param name name of the binary that uses the library * @return FALSE if integrity check failed */ -bool libcharon_init(); +bool libcharon_init(const char *name); /** * Deinitialize libcharon and destroy the "charon" instance of daemon_t. diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 60fa7e0c4..2dfaf43df 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -108,6 +109,11 @@ struct private_generator_t { * to hold the length of the transform attribute in bytes. */ u_int16_t attribute_length; + + /** + * TRUE, if debug messages should be logged during generation. + */ + bool debug; }; /** @@ -155,8 +161,11 @@ static void make_space_available(private_generator_t *this, int bits) new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE; out_position_offset = this->out_position - this->buffer; - DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", - old_buffer_size, new_buffer_size); + if (this->debug) + { + DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", + old_buffer_size, new_buffer_size); + } this->buffer = realloc(this->buffer,new_buffer_size); this->out_position = (this->buffer + out_position_offset); @@ -205,7 +214,7 @@ static void generate_u_int_type(private_generator_t *this, break; case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: number_of_bits = 16; break; case U_INT_32: @@ -244,7 +253,10 @@ static void generate_u_int_type(private_generator_t *this, low = *(this->out_position) & 0x0F; /* high is set, low_val is not changed */ *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } /* write position is not changed, just bit position is moved */ this->current_bit = 4; } @@ -255,7 +267,10 @@ static void generate_u_int_type(private_generator_t *this, /* low of current byte in buffer has to be set to the new value*/ low = *((u_int8_t *)(this->data_struct + offset)) & 0x0F; *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; this->current_bit = 0; } @@ -274,7 +289,10 @@ static void generate_u_int_type(private_generator_t *this, { /* 8 bit values are written as they are */ *this->out_position = *((u_int8_t *)(this->data_struct + offset)); - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; break; } @@ -299,7 +317,10 @@ static void generate_u_int_type(private_generator_t *this, val |= 0x8000; } val = htons(val); - DBG3(DBG_ENC, " => %d", val); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", val); + } /* write bytes to buffer (set bit is overwritten) */ write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); this->current_bit = 0; @@ -308,17 +329,23 @@ static void generate_u_int_type(private_generator_t *this, } case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int16_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); break; } case U_INT_32: { u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int32_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int32_t)); break; } @@ -327,8 +354,11 @@ static void generate_u_int_type(private_generator_t *this, /* 64 bit are written as-is, no host order conversion */ write_bytes_to_buffer(this, this->data_struct + offset, sizeof(u_int64_t)); - DBG3(DBG_ENC, " => %b", this->data_struct + offset, - sizeof(u_int64_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", this->data_struct + offset, + sizeof(u_int64_t)); + } break; } default: @@ -361,7 +391,10 @@ static void generate_flag(private_generator_t *this, u_int32_t offset) } *(this->out_position) = *(this->out_position) | flag; - DBG3(DBG_ENC, " => %d", *this->out_position); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *this->out_position); + } this->current_bit++; if (this->current_bit >= 8) @@ -380,12 +413,16 @@ static void generate_from_chunk(private_generator_t *this, u_int32_t offset) if (this->current_bit != 0) { - DBG1(DBG_ENC, "can not generate a chunk at Bitpos %d", this->current_bit); + DBG1(DBG_ENC, "can not generate a chunk at bitpos %d", + this->current_bit); return ; } value = (chunk_t *)(this->data_struct + offset); - DBG3(DBG_ENC, " => %B", value); + if (this->debug) + { + DBG3(DBG_ENC, " %B", value); + } write_bytes_to_buffer(this, value->ptr, value->len); } @@ -397,15 +434,17 @@ METHOD(generator_t, get_chunk, chunk_t, *lenpos = (u_int32_t*)(this->buffer + this->header_length_offset); data = chunk_create(this->buffer, get_length(this)); - DBG3(DBG_ENC, "generated data of this generator %B", &data); + if (this->debug) + { + DBG3(DBG_ENC, "generated data of this generator %B", &data); + } return data; } METHOD(generator_t, generate_payload, void, - private_generator_t *this,payload_t *payload) + private_generator_t *this, payload_t *payload) { - int i, offset_start; - size_t rule_count; + int i, offset_start, rule_count; encoding_rule_t *rules; payload_type_t payload_type; @@ -414,17 +453,23 @@ METHOD(generator_t, generate_payload, void, offset_start = this->out_position - this->buffer; - DBG2(DBG_ENC, "generating payload of type %N", - payload_type_names, payload_type); + if (this->debug) + { + DBG2(DBG_ENC, "generating payload of type %N", + payload_type_names, payload_type); + } /* each payload has its own encoding rules */ - payload->get_encoding_rules(payload, &rules, &rule_count); + rule_count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < rule_count;i++) { - DBG2(DBG_ENC, " generating rule %d %N", - i, encoding_type_names, rules[i].type); - switch (rules[i].type) + if (this->debug) + { + DBG2(DBG_ENC, " generating rule %d %N", + i, encoding_type_names, rules[i].type); + } + switch ((int)rules[i].type) { case U_INT_4: case U_INT_8: @@ -436,7 +481,7 @@ METHOD(generator_t, generate_payload, void, case SPI_SIZE: case TS_TYPE: case ATTRIBUTE_TYPE: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: generate_u_int_type(this, rules[i].type, rules[i].offset); break; case RESERVED_BIT: @@ -449,26 +494,19 @@ METHOD(generator_t, generate_payload, void, break; case ADDRESS: case SPI: - case KEY_EXCHANGE_DATA: - case NOTIFICATION_DATA: - case NONCE_DATA: - case ID_DATA: - case AUTH_DATA: - case CERT_DATA: - case CERTREQ_DATA: - case SPIS: - case CONFIGURATION_ATTRIBUTE_VALUE: - case VID_DATA: - case EAP_DATA: + case CHUNK_DATA: case ENCRYPTED_DATA: - case UNKNOWN_DATA: generate_from_chunk(this, rules[i].offset); break; - case PROPOSALS: - case TRANSFORMS: - case TRANSFORM_ATTRIBUTES: - case CONFIGURATION_ATTRIBUTES: - case TRAFFIC_SELECTORS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { linked_list_t *proposals; enumerator_t *enumerator; @@ -507,7 +545,10 @@ METHOD(generator_t, generate_payload, void, { if (!this->attribute_format) { - DBG2(DBG_ENC, "attribute value has not fixed size"); + if (this->debug) + { + DBG2(DBG_ENC, "attribute value has not fixed size"); + } /* the attribute value is generated */ generate_from_chunk(this, rules[i].offset); } @@ -519,11 +560,14 @@ METHOD(generator_t, generate_payload, void, return; } } - DBG2(DBG_ENC, "generating %N payload finished", - payload_type_names, payload_type); - DBG3(DBG_ENC, "generated data for this payload %b", - this->buffer + offset_start, - (u_int)(this->out_position - this->buffer - offset_start)); + if (this->debug) + { + DBG2(DBG_ENC, "generating %N payload finished", + payload_type_names, payload_type); + DBG3(DBG_ENC, "generated data for this payload %b", + this->buffer + offset_start, + (u_int)(this->out_position - this->buffer - offset_start)); + } } METHOD(generator_t, destroy, void, @@ -547,6 +591,7 @@ generator_t *generator_create() .destroy = _destroy, }, .buffer = malloc(GENERATOR_DATA_BUFFER_SIZE), + .debug = TRUE, ); this->out_position = this->buffer; @@ -555,3 +600,14 @@ generator_t *generator_create() return &this->public; } +/* + * Described in header + */ +generator_t *generator_create_no_dbg() +{ + private_generator_t *this = (private_generator_t*)generator_create(); + + this->debug = FALSE; + + return &this->public; +} diff --git a/src/libcharon/encoding/generator.h b/src/libcharon/encoding/generator.h index fe561fdfd..c2c0aad2a 100644 --- a/src/libcharon/encoding/generator.h +++ b/src/libcharon/encoding/generator.h @@ -72,4 +72,12 @@ struct generator_t { */ generator_t *generator_create(void); +/** + * Constructor to create a generator that does not log any debug messages > 1. + * + * @return generator_t object. + */ +generator_t *generator_create_no_dbg(void); + + #endif /** GENERATOR_H_ @}*/ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 2b5399294..d3b72ea95 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2006 Daniel Roethlisberger @@ -24,36 +24,46 @@ #include #include -#include +#include #include #include -#include #include #include +#include #include #include #include /** - * Max number of notify payloads per IKEv2 Message + * Max number of notify payloads per IKEv2 message */ #define MAX_NOTIFY_PAYLOADS 20 /** - * Max number of delete payloads per IKEv2 Message + * Max number of delete payloads per IKEv2 message */ #define MAX_DELETE_PAYLOADS 20 /** - * Max number of certificate payloads per IKEv2 Message + * Max number of certificate payloads per IKEv2 message */ #define MAX_CERT_PAYLOADS 8 /** - * Max number of Vendor ID payloads per IKEv2 Message + * Max number of vendor ID payloads per IKEv2 message */ #define MAX_VID_PAYLOADS 20 +/** + * Max number of certificate request payloads per IKEv1 message + */ +#define MAX_CERTREQ_PAYLOADS 5 + +/** + * Max number of NAT-D payloads per IKEv1 message + */ +#define MAX_NAT_D_PAYLOADS 5 + /** * A payload rule defines the rules for a payload * in a specific message rule. It defines if and how @@ -414,6 +424,273 @@ static payload_order_t me_connect_r_order[] = { }; #endif /* ME */ +#ifdef USE_IKEV1 +/** + * Message rule for ID_PROT from initiator. + */ +static payload_rule_t id_prot_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from initiator. + */ +static payload_order_t id_prot_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, +}; + +/** + * Message rule for ID_PROT from responder. + */ +static payload_rule_t id_prot_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from responder. + */ +static payload_order_t id_prot_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, +}; + +/** + * Message rule for AGGRESSIVE from initiator. + */ +static payload_rule_t aggressive_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from initiator. + */ +static payload_order_t aggressive_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for AGGRESSIVE from responder. + */ +static payload_rule_t aggressive_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, + {SIGNATURE_V1, 0, 1, FALSE, FALSE}, + {HASH_V1, 0, 1, FALSE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from responder. + */ +static payload_order_t aggressive_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for INFORMATIONAL_V1 from initiator. + */ +static payload_rule_t informational_i_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from initiator. + */ +static payload_order_t informational_i_order_v1[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for INFORMATIONAL_V1 from responder. + */ +static payload_rule_t informational_r_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from responder. + */ +static payload_order_t informational_r_order_v1[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for QUICK_MODE from initiator. + */ +static payload_rule_t quick_mode_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from initiator. + */ +static payload_order_t quick_mode_i_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, + {NAT_OA_V1, 0}, +}; + +/** + * Message rule for QUICK_MODE from responder. + */ +static payload_rule_t quick_mode_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from responder. + */ +static payload_order_t quick_mode_r_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, + {NAT_OA_V1, 0}, +}; + +/** + * Message rule for TRANSACTION. + */ +static payload_rule_t transaction_payload_rules_v1[] = { +/* payload type min max encr suff */ + {HASH_V1, 0, 1, TRUE, FALSE}, + {CONFIGURATION_V1, 1, 1, FALSE, FALSE}, +}; + +/** + * Payload order for TRANSACTION. + */ +static payload_order_t transaction_payload_order_v1[] = { +/* payload type notify type */ + {HASH_V1, 0}, + {CONFIGURATION_V1, 0}, +}; + +#endif /* USE_IKEV1 */ + /** * Message rules, defines allowed payloads. */ @@ -460,6 +737,49 @@ static message_rule_t message_rules[] = { countof(me_connect_r_order), me_connect_r_order, }, #endif /* ME */ +#ifdef USE_IKEV1 + {ID_PROT, TRUE, FALSE, + countof(id_prot_i_rules), id_prot_i_rules, + countof(id_prot_i_order), id_prot_i_order, + }, + {ID_PROT, FALSE, FALSE, + countof(id_prot_r_rules), id_prot_r_rules, + countof(id_prot_r_order), id_prot_r_order, + }, + {AGGRESSIVE, TRUE, FALSE, + countof(aggressive_i_rules), aggressive_i_rules, + countof(aggressive_i_order), aggressive_i_order, + }, + {AGGRESSIVE, FALSE, FALSE, + countof(aggressive_r_rules), aggressive_r_rules, + countof(aggressive_r_order), aggressive_r_order, + }, + {INFORMATIONAL_V1, TRUE, TRUE, + countof(informational_i_rules_v1), informational_i_rules_v1, + countof(informational_i_order_v1), informational_i_order_v1, + }, + {INFORMATIONAL_V1, FALSE, TRUE, + countof(informational_r_rules_v1), informational_r_rules_v1, + countof(informational_r_order_v1), informational_r_order_v1, + }, + {QUICK_MODE, TRUE, TRUE, + countof(quick_mode_i_rules), quick_mode_i_rules, + countof(quick_mode_i_order), quick_mode_i_order, + }, + {QUICK_MODE, FALSE, TRUE, + countof(quick_mode_r_rules), quick_mode_r_rules, + countof(quick_mode_r_order), quick_mode_r_order, + }, + {TRANSACTION, TRUE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, + {TRANSACTION, FALSE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, + /* TODO-IKEv1: define rules for other exchanges */ +#endif /* USE_IKEV1 */ }; @@ -500,6 +820,11 @@ struct private_message_t { */ bool is_request; + /** + * The message is encrypted (IKEv1) + */ + bool is_encrypted; + /** * Higher version supported? */ @@ -508,7 +833,7 @@ struct private_message_t { /** * Reserved bits in IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Sorting of message disabled? @@ -739,7 +1064,14 @@ METHOD(message_t, add_notify, void, payload->destroy(payload); } } - notify = notify_payload_create(); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + notify = notify_payload_create(NOTIFY); + } + else + { + notify = notify_payload_create(NOTIFY_V1); + } notify->set_notify_type(notify, type); notify->set_notification_data(notify, data); add_payload(this, (payload_t*)notify); @@ -810,7 +1142,8 @@ METHOD(message_t, get_notify, notify_payload_t*, enumerator = create_payload_enumerator(this); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == type) @@ -837,7 +1170,7 @@ static char* get_string(private_message_t *this, char *buf, int len) memset(buf, 0, len); len--; - written = snprintf(pos, len, "%N %s %d [", + written = snprintf(pos, len, "%N %s %u [", exchange_type_names, this->exchange_type, this->is_request ? "request" : "response", this->message_id); @@ -859,7 +1192,8 @@ static char* get_string(private_message_t *this, char *buf, int len) } pos += written; len -= written; - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify_payload_t *notify; notify_type_t type; @@ -1017,7 +1351,7 @@ static void order_payloads(private_message_t *this) } /** - * Wrap payloads in a encryption payload + * Wrap payloads in an encryption payload */ static encryption_payload_t* wrap_payloads(private_message_t *this) { @@ -1033,7 +1367,14 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) payloads->insert_last(payloads, current); } - encryption = encryption_payload_create(); + if (this->is_encrypted) + { + encryption = encryption_payload_create(ENCRYPTED_V1); + } + else + { + encryption = encryption_payload_create(ENCRYPTED); + } while (payloads->remove_first(payloads, (void**)¤t) == SUCCESS) { payload_rule_t *rule; @@ -1046,8 +1387,8 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) { encrypt = rule->encrypted; } - if (encrypt) - { + if (encrypt || this->is_encrypted) + { /* encryption is forced for IKEv1 */ DBG2(DBG_ENC, "insert payload %N to encryption payload", payload_type_names, type); encryption->add_payload(encryption, current); @@ -1071,17 +1412,20 @@ METHOD(message_t, disable_sort, void, } METHOD(message_t, generate, status_t, - private_message_t *this, aead_t *aead, packet_t **packet) + private_message_t *this, keymat_t *keymat, packet_t **packet) { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; generator_t *generator; ike_header_t *ike_header; payload_t *payload, *next; encryption_payload_t *encryption = NULL; + payload_type_t next_type; enumerator_t *enumerator; - chunk_t chunk; + aead_t *aead = NULL; + chunk_t chunk, hash = chunk_empty; char str[BUF_LEN]; u_int32_t *lenpos; - bool *reserved; + bool encrypted = FALSE, *reserved; int i; if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) @@ -1108,27 +1452,77 @@ METHOD(message_t, generate, status_t, { order_payloads(this); } + if (keymat && keymat->get_version(keymat) == IKEV1) + { + /* get a hash for this message, if any is required */ + if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash)) + { /* insert a HASH payload as first payload */ + hash_payload_t *hash_payload; + + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + this->payloads->insert_first(this->payloads, hash_payload); + if (this->exchange_type == INFORMATIONAL_V1) + { + this->is_encrypted = encrypted = TRUE; + } + chunk_free(&hash); + } + } + if (this->major_version == IKEV2_MAJOR_VERSION) + { + encrypted = this->rule->encrypted; + } + else if (!encrypted) + { + /* If at least one payload requires encryption, encrypt the message. + * If no key material is available, the flag will be reset below. */ + enumerator = this->payloads->create_enumerator(this->payloads); + while (enumerator->enumerate(enumerator, (void**)&payload)) + { + payload_rule_t *rule; + + rule = get_payload_rule(this, payload->get_type(payload)); + if (rule && rule->encrypted) + { + this->is_encrypted = encrypted = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - if (aead && this->rule->encrypted) + if (keymat) + { + aead = keymat->get_aead(keymat, FALSE); + } + if (aead && encrypted) { encryption = wrap_payloads(this); } else { DBG2(DBG_ENC, "not encrypting payloads"); + this->is_encrypted = FALSE; } - ike_header = ike_header_create(); - ike_header->set_maj_version(ike_header, this->major_version); - ike_header->set_min_version(ike_header, this->minor_version); + ike_header = ike_header_create_version(this->major_version, + this->minor_version); ike_header->set_exchange_type(ike_header, this->exchange_type); ike_header->set_message_id(ike_header, this->message_id); - ike_header->set_response_flag(ike_header, !this->is_request); - ike_header->set_version_flag(ike_header, this->version_flag); - ike_header->set_initiator_flag(ike_header, + if (this->major_version == IKEV2_MAJOR_VERSION) + { + ike_header->set_response_flag(ike_header, !this->is_request); + ike_header->set_version_flag(ike_header, this->version_flag); + ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id)); + } + else + { + ike_header->set_encryption_flag(ike_header, this->is_encrypted); + } ike_header->set_initiator_spi(ike_header, this->ike_sa_id->get_initiator_spi(this->ike_sa_id)); ike_header->set_responder_spi(ike_header, @@ -1156,22 +1550,38 @@ METHOD(message_t, generate, status_t, payload = next; } enumerator->destroy(enumerator); - payload->set_next_type(payload, encryption ? ENCRYPTED : NO_PAYLOAD); + if (this->is_encrypted) + { /* for encrypted IKEv1 messages */ + next_type = encryption->payload_interface.get_next_type( + (payload_t*)encryption); + } + else + { + next_type = encryption ? ENCRYPTED : NO_PAYLOAD; + } + payload->set_next_type(payload, next_type); generator->generate_payload(generator, payload); ike_header->destroy(ike_header); if (encryption) - { - u_int32_t *lenpos; - - /* build associated data (without header of encryption payload) */ - chunk = generator->get_chunk(generator, &lenpos); + { /* set_transform() has to be called before get_length() */ encryption->set_transform(encryption, aead); - /* fill in length, including encryption payload */ - htoun32(lenpos, chunk.len + encryption->get_length(encryption)); - + if (this->is_encrypted) + { /* for IKEv1 instead of associated data we provide the IV */ + if (!keymat_v1->get_iv(keymat_v1, this->message_id, &chunk)) + { + generator->destroy(generator); + return FAILED; + } + } + else + { /* build associated data (without header of encryption payload) */ + chunk = generator->get_chunk(generator, &lenpos); + /* fill in length, including encryption payload */ + htoun32(lenpos, chunk.len + encryption->get_length(encryption)); + } this->payloads->insert_last(this->payloads, encryption); - if (!encryption->encrypt(encryption, chunk)) + if (encryption->encrypt(encryption, chunk) != SUCCESS) { generator->destroy(generator); return INVALID_STATE; @@ -1181,8 +1591,22 @@ METHOD(message_t, generate, status_t, chunk = generator->get_chunk(generator, &lenpos); htoun32(lenpos, chunk.len); this->packet->set_data(this->packet, chunk_clone(chunk)); + if (this->is_encrypted) + { + /* update the IV for the next IKEv1 message */ + chunk_t last_block; + size_t bs; + + bs = aead->get_block_size(aead); + last_block = chunk_create(chunk.ptr + chunk.len - bs, bs); + if (!keymat_v1->update_iv(keymat_v1, this->message_id, last_block) || + !keymat_v1->confirm_iv(keymat_v1, this->message_id)) + { + generator->destroy(generator); + return FAILED; + } + } generator->destroy(generator); - *packet = this->packet->clone(this->packet); return SUCCESS; } @@ -1204,7 +1628,7 @@ METHOD(message_t, get_packet_data, chunk_t, { return chunk_empty; } - return chunk_clone(this->packet->get_data(this->packet)); + return this->packet->get_data(this->packet); } METHOD(message_t, parse_header, status_t, @@ -1237,15 +1661,24 @@ METHOD(message_t, parse_header, status_t, } DESTROY_IF(this->ike_sa_id); - this->ike_sa_id = ike_sa_id_create(ike_header->get_initiator_spi(ike_header), + this->ike_sa_id = ike_sa_id_create( + ike_header->get_maj_version(ike_header), + ike_header->get_initiator_spi(ike_header), ike_header->get_responder_spi(ike_header), ike_header->get_initiator_flag(ike_header)); this->exchange_type = ike_header->get_exchange_type(ike_header); this->message_id = ike_header->get_message_id(ike_header); - this->is_request = !ike_header->get_response_flag(ike_header); this->major_version = ike_header->get_maj_version(ike_header); this->minor_version = ike_header->get_min_version(ike_header); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + this->is_request = !ike_header->get_response_flag(ike_header); + } + else + { + this->is_encrypted = ike_header->get_encryption_flag(ike_header); + } this->first_payload = ike_header->payload_interface.get_next_type( &ike_header->payload_interface); for (i = 0; i < countof(this->reserved); i++) @@ -1257,19 +1690,12 @@ METHOD(message_t, parse_header, status_t, this->reserved[i] = *reserved; } } - DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - ike_header->destroy(ike_header); - this->rule = get_message_rule(this); - if (!this->rule) - { - DBG1(DBG_ENC, "no message rules specified for a %N %s", - exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - } - return status; + DBG2(DBG_ENC, "parsed a %N %s header", exchange_type_names, + this->exchange_type, this->major_version == IKEV1_MAJOR_VERSION ? + "message" : (this->is_request ? "request" : "response")); + return SUCCESS; } /** @@ -1297,16 +1723,84 @@ static bool is_connectivity_check(private_message_t *this, payload_t *payload) return FALSE; } +/** + * Parses and verifies the unencrypted payloads contained in the message + */ +static status_t parse_payloads(private_message_t *this) +{ + payload_type_t type = this->first_payload; + payload_t *payload; + status_t status; + + if (this->is_encrypted) + { /* wrap the whole encrypted IKEv1 message in a special encryption + * payload which is then handled just like a regular payload */ + encryption_payload_t *encryption; + + status = this->parser->parse_payload(this->parser, ENCRYPTED_V1, + (payload_t**)&encryption); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "failed to wrap encrypted IKEv1 message"); + return PARSE_ERROR; + } + encryption->payload_interface.set_next_type((payload_t*)encryption, + this->first_payload); + this->payloads->insert_last(this->payloads, encryption); + return SUCCESS; + } + + while (type != NO_PAYLOAD) + { + DBG2(DBG_ENC, "starting parsing a %N payload", + payload_type_names, type); + + status = this->parser->parse_payload(this->parser, type, &payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "payload type %N could not be parsed", + payload_type_names, type); + return PARSE_ERROR; + } + + DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); + status = payload->verify(payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "%N payload verification failed", + payload_type_names, type); + payload->destroy(payload); + return VERIFY_ERROR; + } + + DBG2(DBG_ENC, "%N payload verified. Adding to payload list", + payload_type_names, type); + this->payloads->insert_last(this->payloads, payload); + + /* an encryption payload is the last one, so STOP here. decryption is + * done later */ + if (type == ENCRYPTED) + { + DBG2(DBG_ENC, "%N payload found. Stop parsing", + payload_type_names, type); + break; + } + type = payload->get_next_type(payload); + } + return SUCCESS; +} + /** * Decrypt payload from the encryption payload */ -static status_t decrypt_payloads(private_message_t *this, aead_t *aead) +static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) { bool was_encrypted = FALSE; payload_t *payload, *previous = NULL; enumerator_t *enumerator; payload_rule_t *rule; payload_type_t type; + aead_t *aead; status_t status = SUCCESS; enumerator = this->payloads->create_enumerator(this->payloads); @@ -1316,11 +1810,12 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) DBG2(DBG_ENC, "process payload of type %N", payload_type_names, type); - if (type == ENCRYPTED) + if (type == ENCRYPTED || type == ENCRYPTED_V1) { encryption_payload_t *encryption; payload_t *encrypted; chunk_t chunk; + size_t bs; encryption = (encryption_payload_t*)payload; @@ -1332,16 +1827,57 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) status = VERIFY_ERROR; break; } + if (!keymat) + { + DBG1(DBG_ENC, "found encryption payload, but no keymat"); + status = INVALID_ARG; + break; + } + aead = keymat->get_aead(keymat, TRUE); + if (!aead) + { + DBG1(DBG_ENC, "found encryption payload, but no transform set"); + status = INVALID_ARG; + break; + } + bs = aead->get_block_size(aead); encryption->set_transform(encryption, aead); chunk = this->packet->get_data(this->packet); - if (chunk.len < encryption->get_length(encryption)) + if (chunk.len < encryption->get_length(encryption) || + chunk.len < bs) { DBG1(DBG_ENC, "invalid payload length"); status = VERIFY_ERROR; break; } - chunk.len -= encryption->get_length(encryption); - status = encryption->decrypt(encryption, chunk); + if (keymat->get_version(keymat) == IKEV1) + { /* instead of associated data we provide the IV, we also update + * the IV with the last encrypted block */ + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t iv; + + if (keymat_v1->get_iv(keymat_v1, this->message_id, &iv)) + { + status = encryption->decrypt(encryption, iv); + if (status == SUCCESS) + { + if (!keymat_v1->update_iv(keymat_v1, this->message_id, + chunk_create(chunk.ptr + chunk.len - bs, bs))) + { + status = FAILED; + } + } + } + else + { + status = FAILED; + } + } + else + { + chunk.len -= encryption->get_length(encryption); + status = encryption->decrypt(encryption, chunk); + } if (status != SUCCESS) { break; @@ -1369,7 +1905,8 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) encryption->destroy(encryption); } if (payload_is_known(type) && !was_encrypted && - !is_connectivity_check(this, payload)) + !is_connectivity_check(this, payload) && + this->exchange_type != AGGRESSIVE) { rule = get_payload_rule(this, type); if (!rule || rule->encrypted) @@ -1396,7 +1933,7 @@ static status_t verify(private_message_t *this) DBG2(DBG_ENC, "verifying message structure"); - /* check for payloads with wrong count*/ + /* check for payloads with wrong count */ for (i = 0; i < this->rule->rule_count; i++) { enumerator_t *enumerator; @@ -1443,57 +1980,30 @@ static status_t verify(private_message_t *this) } METHOD(message_t, parse_body, status_t, - private_message_t *this, aead_t *aead) + private_message_t *this, keymat_t *keymat) { status_t status = SUCCESS; - payload_t *payload; - payload_type_t type; char str[BUF_LEN]; - type = this->first_payload; - DBG2(DBG_ENC, "parsing body of message, first payload is %N", - payload_type_names, type); + payload_type_names, this->first_payload); - while (type != NO_PAYLOAD) + this->rule = get_message_rule(this); + if (!this->rule) { - DBG2(DBG_ENC, "starting parsing a %N payload", - payload_type_names, type); - - status = this->parser->parse_payload(this->parser, type, &payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "payload type %N could not be parsed", - payload_type_names, type); - return this->exchange_type == IKE_SA_INIT ? PARSE_ERROR : FAILED; - } - - DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); - status = payload->verify(payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "%N payload verification failed", - payload_type_names, type); - payload->destroy(payload); - return this->exchange_type == IKE_SA_INIT ? VERIFY_ERROR : FAILED; - } - - DBG2(DBG_ENC, "%N payload verified. Adding to payload list", - payload_type_names, type); - this->payloads->insert_last(this->payloads, payload); + DBG1(DBG_ENC, "no message rules specified for a %N %s", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response"); + return NOT_SUPPORTED; + } - /* an encryption payload is the last one, so STOP here. decryption is - * done later */ - if (type == ENCRYPTED) - { - DBG2(DBG_ENC, "%N payload found. Stop parsing", - payload_type_names, type); - break; - } - type = payload->get_next_type(payload); + status = parse_payloads(this); + if (status != SUCCESS) + { /* error is already logged */ + return status; } - status = decrypt_payloads(this, aead); + status = decrypt_payloads(this, keymat); if (status != SUCCESS) { DBG1(DBG_ENC, "could not decrypt payloads"); @@ -1508,6 +2018,50 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); + if (keymat && keymat->get_version(keymat) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t hash; + + if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash)) + { + hash_payload_t *hash_payload; + chunk_t other_hash; + + if (this->first_payload != HASH_V1) + { + if (this->exchange_type == INFORMATIONAL_V1) + { + DBG1(DBG_ENC, "ignoring unprotected INFORMATIONAL from %H", + this->packet->get_source(this->packet)); + } + else + { + DBG1(DBG_ENC, "expected HASH payload as first payload"); + } + chunk_free(&hash); + return VERIFY_ERROR; + } + hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); + other_hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_ENC, "HASH received %B\nHASH expected %B", + &other_hash, &hash); + if (!chunk_equals(hash, other_hash)) + { + DBG1(DBG_ENC, "received HASH payload does not match"); + chunk_free(&hash); + return FAILED; + } + chunk_free(&hash); + } + if (this->is_encrypted) + { /* message verified, confirm IV */ + if (!keymat_v1->confirm_iv(keymat_v1, this->message_id)) + { + return FAILED; + } + } + } return SUCCESS; } @@ -1522,7 +2076,7 @@ METHOD(message_t, destroy, void, } /* - * Described in Header-File + * Described in header. */ message_t *message_create_from_packet(packet_t *packet) { @@ -1567,8 +2121,6 @@ message_t *message_create_from_packet(packet_t *packet) .get_packet_data = _get_packet_data, .destroy = _destroy, }, - .major_version = IKE_MAJOR_VERSION, - .minor_version = IKE_MINOR_VERSION, .exchange_type = EXCHANGE_TYPE_UNDEFINED, .is_request = TRUE, .first_payload = NO_PAYLOAD, @@ -1577,14 +2129,18 @@ message_t *message_create_from_packet(packet_t *packet) .parser = parser_create(packet->get_data(packet)), ); - return (&this->public); + return &this->public; } /* - * Described in Header. + * Described in header. */ -message_t *message_create() +message_t *message_create(int major, int minor) { - return message_create_from_packet(packet_create()); -} + message_t *this = message_create_from_packet(packet_create()); + this->set_major_version(this, major); + this->set_minor_version(this, minor); + + return this; +} diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index 0e78ea436..6d558daf6 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -27,15 +27,15 @@ typedef struct message_t message_t; #include -#include -#include #include #include +#include +#include +#include #include -#include /** - * This class is used to represent an IKEv2-Message. + * This class is used to represent an IKE-Message. * * The message handles parsing and generation of payloads * via parser_t/generator_t. Encryption is done transparently @@ -182,7 +182,7 @@ struct message_t { * all payloads to encrypt are added to the encryption payload, which is * always the last one. * - * @param payload payload to append + * @param payload payload to append */ void (*add_payload) (message_t *this, payload_t *payload); @@ -208,14 +208,14 @@ struct message_t { /** * Parses header of message. * - * Begins parisng of a message created via message_create_from_packet(). + * Begins parsing of a message created via message_create_from_packet(). * The parsing context is stored, so a subsequent call to parse_body() * will continue the parsing process. * * @return - * - SUCCESS if header could be parsed + * - SUCCESS if header could be parsed * - PARSE_ERROR if corrupted/invalid data found - * - FAILED if consistence check of header failed + * - FAILED if consistency check of header failed */ status_t (*parse_header) (message_t *this); @@ -228,15 +228,15 @@ struct message_t { * If there are encrypted payloads, they get decrypted and verified using * the given aead transform (if given). * - * @param aead aead transform to verify/decrypt message + * @param keymat keymat to verify/decrypt message * @return - * - SUCCESS if parsing successful + * - SUCCESS if parsing successful * - PARSE_ERROR if message parsing failed - * - VERIFY_ERROR if message verification failed (bad syntax) - * - FAILED if integrity check failed - * - INVALID_STATE if aead not supplied, but needed + * - VERIFY_ERROR if message verification failed (bad syntax) + * - FAILED if integrity check failed + * - INVALID_STATE if aead not supplied, but needed */ - status_t (*parse_body) (message_t *this, aead_t *aead); + status_t (*parse_body) (message_t *this, keymat_t *keymat); /** * Generates the UDP packet of specific message. @@ -247,15 +247,15 @@ struct message_t { * Generation is only done once, multiple calls will just return a copy * of the packet. * - * @param aead aead transform to encrypt/sign message + * @param keymat keymat to encrypt/sign message * @param packet copy of generated packet * @return - * - SUCCESS if packet could be generated - * - INVALID_STATE if exchange type is currently not set - * - NOT_FOUND if no rules found for message generation - * - INVALID_STATE if aead not supplied but needed. + * - SUCCESS if packet could be generated + * - INVALID_STATE if exchange type is currently not set + * - NOT_FOUND if no rules found for message generation + * - INVALID_STATE if aead not supplied but needed. */ - status_t (*generate) (message_t *this, aead_t *aead, packet_t **packet); + status_t (*generate) (message_t *this, keymat_t *keymat, packet_t **packet); /** * Check if the message has already been encoded using generate(). @@ -278,7 +278,7 @@ struct message_t { * Sets the source host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_source. + * message_t.destroy or next call of message_t.set_source. * * @param host host_t object representing source host */ @@ -298,7 +298,7 @@ struct message_t { * Sets the destination host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_destination. + * message_t.destroy or next call of message_t.set_destination. * * @param host host_t object representing destination host */ @@ -344,9 +344,9 @@ struct message_t { packet_t * (*get_packet) (message_t *this); /** - * Returns a clone of the internal stored packet_t data. + * Returns a chunk pointing to internal packet_t data. * - * @return clone of the internal stored packet_t data. + * @return packet data. */ chunk_t (*get_packet_data) (message_t *this); @@ -357,26 +357,27 @@ struct message_t { }; /** - * Creates an message_t object from a incoming UDP Packet. + * Creates a message_t object from an incoming UDP packet. * * The given packet gets owned by the message. The message is uninitialized, * call parse_header() to populate header fields. * * @param packet packet_t object which is assigned to message - * @return message_t object + * @return message_t object */ -message_t * message_create_from_packet(packet_t *packet); - +message_t *message_create_from_packet(packet_t *packet); /** - * Creates an empty message_t object. + * Creates an empty message_t object for a specific major/minor version. * * - exchange_type is set to NOT_SET * - original_initiator is set to TRUE * - is_request is set to TRUE * - * @return message_t object + * @param major major IKE version of this message + * @param minor minor IKE version of this message + * @return message_t object */ -message_t * message_create(void); +message_t *message_create(int major, int minor); #endif /** MESSAGE_H_ @}*/ diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index e49210309..e4b140c3e 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -137,7 +137,7 @@ static bool parse_uint4(private_parser_t *this, int rule_number, } if (output_pos) { - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } return TRUE; } @@ -159,7 +159,7 @@ static bool parse_uint8(private_parser_t *this, int rule_number, if (output_pos) { *output_pos = *(this->byte_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } this->byte_pos++; return TRUE; @@ -183,7 +183,7 @@ static bool parse_uint15(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos) & ~0x8000; - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); this->bit_pos = 0; @@ -208,7 +208,7 @@ static bool parse_uint16(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); return TRUE; @@ -231,7 +231,7 @@ static bool parse_uint32(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int32_t)); *output_pos = ntohl(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %u", *output_pos); } this->byte_pos += sizeof(u_int32_t); return TRUE; @@ -254,7 +254,7 @@ static bool parse_bytes(private_parser_t *this, int rule_number, if (output_pos) { memcpy(output_pos, this->byte_pos, bytes); - DBG3(DBG_ENC, " => %b", output_pos, bytes); + DBG3(DBG_ENC, " %b", output_pos, bytes); } this->byte_pos += bytes; return TRUE; @@ -352,7 +352,7 @@ static bool parse_chunk(private_parser_t *this, int rule_number, { *output_pos = chunk_alloc(length); memcpy(output_pos->ptr, this->byte_pos, length); - DBG3(DBG_ENC, " => %b", output_pos->ptr, length); + DBG3(DBG_ENC, " %b", output_pos->ptr, length); } this->byte_pos += length; return TRUE; @@ -363,11 +363,10 @@ METHOD(parser_t, parse_payload, status_t, { payload_t *pld; void *output; - size_t rule_count; - int payload_length = 0, spi_size = 0, attribute_length = 0; + int payload_length = 0, spi_size = 0, attribute_length = 0, header_length; u_int16_t ts_type = 0; bool attribute_format = FALSE; - int rule_number; + int rule_number, rule_count; encoding_rule_t *rule; /* create instance of the payload to parse */ @@ -381,15 +380,17 @@ METHOD(parser_t, parse_payload, status_t, /* base pointer for output, avoids casting in every rule */ output = pld; - /* parse the payload with its own rulse */ - pld->get_encoding_rules(pld, &this->rules, &rule_count); + rule_count = pld->get_encoding_rules(pld, &this->rules); for (rule_number = 0; rule_number < rule_count; rule_number++) { + /* update header length for each rule, as it is dynamic (SPIs) */ + header_length = pld->get_header_length(pld); + rule = &(this->rules[rule_number]); DBG2(DBG_ENC, " parsing rule %d %N", rule_number, encoding_type_names, rule->type); - switch (rule->type) + switch ((int)rule->type) { case U_INT_4: { @@ -457,7 +458,8 @@ METHOD(parser_t, parse_payload, status_t, } /* parsed u_int16 should be aligned */ payload_length = *(u_int16_t*)(output + rule->offset); - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH) + /* all payloads must have at least 4 bytes header */ + if (payload_length < 4) { pld->destroy(pld); return PARSE_ERROR; @@ -484,49 +486,41 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case PROPOSALS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { - if (payload_length < SA_PAYLOAD_HEADER_LENGTH || + if (payload_length < header_length || !parse_list(this, rule_number, output + rule->offset, - PROPOSAL_SUBSTRUCTURE, - payload_length - SA_PAYLOAD_HEADER_LENGTH)) + rule->type - PAYLOAD_LIST, + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; } break; } - case TRANSFORMS: + case CHUNK_DATA: { - if (payload_length < - spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_SUBSTRUCTURE, payload_length - spi_size - - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case TRANSFORM_ATTRIBUTES: - { - if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_ATTRIBUTE, - payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH)) + if (payload_length < header_length || + !parse_chunk(this, rule_number, output + rule->offset, + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; } break; } - case CONFIGURATION_ATTRIBUTES: + case ENCRYPTED_DATA: { - if (payload_length < CP_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - CONFIGURATION_ATTRIBUTE, - payload_length - CP_PAYLOAD_HEADER_LENGTH)) + if (!parse_chunk(this, rule_number, output + rule->offset, + this->input_roof - this->byte_pos)) { pld->destroy(pld); return PARSE_ERROR; @@ -552,7 +546,7 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { if (!parse_uint16(this, rule_number, output + rule->offset)) { @@ -583,137 +577,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case NONCE_DATA: - { - if (payload_length < NONCE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NONCE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ID_DATA: - { - if (payload_length < ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case AUTH_DATA: - { - if (payload_length < AUTH_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - AUTH_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERT_DATA: - { - if (payload_length < CERT_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERT_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERTREQ_DATA: - { - if (payload_length < CERTREQ_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case EAP_DATA: - { - if (payload_length < EAP_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - EAP_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case SPIS: - { - if (payload_length < DELETE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - DELETE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case VID_DATA: - { - if (payload_length < VENDOR_ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CONFIGURATION_ATTRIBUTE_VALUE: - { - if (!parse_chunk(this, rule_number, output + rule->offset, - attribute_length)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case KEY_EXCHANGE_DATA: - { - if (payload_length < KE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - KE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case NOTIFICATION_DATA: - { - if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ENCRYPTED_DATA: - { - if (payload_length < ENCRYPTION_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TS_TYPE: { if (!parse_uint8(this, rule_number, output + rule->offset)) @@ -736,29 +599,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case TRAFFIC_SELECTORS: - { - if (payload_length < TS_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRAFFIC_SELECTOR_SUBSTRUCTURE, - payload_length - TS_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case UNKNOWN_DATA: - { - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } default: { DBG1(DBG_ENC, " no rule to parse rule %d %N", diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c index cb44a997c..2410a1aaa 100644 --- a/src/libcharon/encoding/payloads/auth_payload.c +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -74,7 +74,7 @@ struct private_auth_payload_t { * The defined offsets are the positions in a object of type * private_auth_payload_t. */ -encoding_rule_t auth_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_auth_payload_t, next_payload) }, /* the critical bit */ @@ -96,7 +96,7 @@ encoding_rule_t auth_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[1]) }, { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[2]) }, /* some auth data bytes, length is defined in PAYLOAD_LENGTH */ - { AUTH_DATA, offsetof(private_auth_payload_t, auth_data) } + { CHUNK_DATA, offsetof(private_auth_payload_t, auth_data) } }; /* @@ -119,11 +119,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_auth_payload_t *this, encoding_rule_t **rules) { - *rules = auth_payload_encodings; - *rule_count = countof(auth_payload_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_auth_payload_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -167,7 +173,7 @@ METHOD(auth_payload_t, set_data, void, { free(this->auth_data.ptr); this->auth_data = chunk_clone(data); - this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len; + this->payload_length = get_header_length(this) + this->auth_data.len; } METHOD(auth_payload_t, get_data, chunk_t, @@ -195,6 +201,7 @@ auth_payload_t *auth_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -208,7 +215,7 @@ auth_payload_t *auth_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = AUTH_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h index e4c4e6ae3..b922d12c8 100644 --- a/src/libcharon/encoding/payloads/auth_payload.h +++ b/src/libcharon/encoding/payloads/auth_payload.h @@ -26,12 +26,7 @@ typedef struct auth_payload_t auth_payload_t; #include #include -#include - -/** - * Length of a auth payload without the auth data in bytes. - */ -#define AUTH_PAYLOAD_HEADER_LENGTH 8 +#include /** * Class representing an IKEv2 AUTH payload. diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index c42cec680..3a230b91e 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -86,6 +86,11 @@ struct private_cert_payload_t { * TRUE if the "Hash and URL" data is invalid */ bool invalid_hash_and_url; + + /** + * The payload type. + */ + payload_type_t type; }; /** @@ -95,7 +100,7 @@ struct private_cert_payload_t { * private_cert_payload_t. * */ -encoding_rule_t cert_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_cert_payload_t, next_payload) }, /* the critical bit */ @@ -113,7 +118,7 @@ encoding_rule_t cert_payload_encodings[] = { /* 1 Byte CERT type*/ { U_INT_8, offsetof(private_cert_payload_t, encoding) }, /* some cert data bytes, length is defined in PAYLOAD_LENGTH */ - { CERT_DATA, offsetof(private_cert_payload_t, data) } + { CHUNK_DATA, offsetof(private_cert_payload_t, data) } }; /* @@ -166,17 +171,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cert_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_cert_payload_t *this) { - *rules = cert_payload_encodings; - *rule_count = countof(cert_payload_encodings); + return 5; } METHOD(payload_t, get_type, payload_type_t, private_cert_payload_t *this) { - return CERTIFICATE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -261,7 +272,7 @@ METHOD2(payload_t, cert_payload_t, destroy, void, /* * Described in header */ -cert_payload_t *cert_payload_create() +cert_payload_t *cert_payload_create(payload_type_t type) { private_cert_payload_t *this; @@ -270,6 +281,7 @@ cert_payload_t *cert_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -283,7 +295,8 @@ cert_payload_t *cert_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CERT_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -291,10 +304,12 @@ cert_payload_t *cert_payload_create() /* * Described in header */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(type); switch (cert->get_type(cert)) { case CERT_X509: @@ -312,7 +327,8 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) free(this); return NULL; } - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } @@ -321,23 +337,29 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) */ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(CERTIFICATE); this->encoding = ENC_X509_HASH_AND_URL; this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url))); - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } /* * Described in header */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data) +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; - this->encoding = type; + this = (private_cert_payload_t*)cert_payload_create(type); + this->encoding = encoding; this->data = data; - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } + diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index 21b503a40..19ed2ccd2 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -30,11 +30,6 @@ typedef enum cert_encoding_t cert_encoding_t; #include #include -/** - * Length of a cert payload without the cert data in bytes. - */ -#define CERT_PAYLOAD_HEADER_LENGTH 5 - /** * Certifcate encodings, as in RFC4306 */ @@ -60,9 +55,7 @@ enum cert_encoding_t { extern enum_name_t *cert_encoding_names; /** - * Class representing an IKEv2 CERT payload. - * - * The CERT payload format is described in RFC section 3.6. + * Class representing an IKEv1/IKEv2 CERT payload. */ struct cert_payload_t { @@ -103,7 +96,6 @@ struct cert_payload_t { */ char *(*get_url)(cert_payload_t *this); - /** * Destroys the cert_payload object. */ @@ -113,23 +105,26 @@ struct cert_payload_t { /** * Creates an empty certificate payload. * + * @param type payload type (for IKEv1 or IKEv2) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create(void); +cert_payload_t *cert_payload_create(payload_type_t type); /** * Creates a certificate payload with an embedded certificate. * + * @param type payload type (for IKEv1 or IKEv2) * @param cert certificate to embed * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert); +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert); /** - * Creates a certificate payload with hash and URL encoding of a certificate. + * Creates an IKEv2 certificate payload with hash and URL encoding. * * @param hash hash of the DER encoded certificate (get's cloned) - * @param url the URL to locate the certificate (get's cloned) + * @param url URL to the certificate * @return cert_payload_t object */ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); @@ -137,10 +132,12 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); /** * Creates a custom certificate payload using type and associated data. * - * @param type encoding type of certificate + * @param type payload type (for IKEv1 or IKEv2) + * @param encoding encoding type of certificate * @param data associated data (gets owned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data); +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data); #endif /** CERT_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index 02015f273..df5e73b5b 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -64,15 +64,17 @@ struct private_certreq_payload_t { * The contained certreq data value. */ chunk_t data; + + /** + * Payload type CERTIFICATE_REQUEST or CERTIFICATE_REQUEST_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a CERTREQ payload - * - * The defined offsets are the positions in a object of type - * private_certreq_payload_t. + * Encoding rules for CERTREQ payload. */ -encoding_rule_t certreq_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_certreq_payload_t, next_payload) }, /* the critical bit */ @@ -90,7 +92,7 @@ encoding_rule_t certreq_payload_encodings[] = { /* 1 Byte CERTREQ type*/ { U_INT_8, offsetof(private_certreq_payload_t, encoding) }, /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */ - { CERTREQ_DATA, offsetof(private_certreq_payload_t, data) } + { CHUNK_DATA, offsetof(private_certreq_payload_t, data) } }; /* @@ -109,7 +111,8 @@ encoding_rule_t certreq_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_certreq_payload_t *this) { - if (this->encoding == ENC_X509_SIGNATURE) + if (this->type == CERTIFICATE_REQUEST && + this->encoding == ENC_X509_SIGNATURE) { if (this->data.len % HASH_SIZE_SHA1) { @@ -121,17 +124,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_certreq_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_certreq_payload_t *this) { - *rules = certreq_payload_encodings; - *rule_count = countof(certreq_payload_encodings); + return 5; } METHOD(payload_t, get_type, payload_type_t, private_certreq_payload_t *this) { - return CERTIFICATE_REQUEST; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -152,6 +161,16 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } +METHOD(certreq_payload_t, get_dn, identification_t*, + private_certreq_payload_t *this) +{ + if (this->data.len) + { + return identification_create_from_encoding(ID_DER_ASN1_DN, this->data); + } + return NULL; +} + METHOD(certreq_payload_t, add_keyid, void, private_certreq_payload_t *this, chunk_t keyid) { @@ -199,6 +218,10 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*, { keyid_enumerator_t *enumerator; + if (this->type == CERTIFICATE_REQUEST_V1) + { + return enumerator_create_empty(); + } INIT(enumerator, .public = { .enumerate = (void*)_keyid_enumerate, @@ -231,7 +254,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void, /* * Described in header */ -certreq_payload_t *certreq_payload_create() +certreq_payload_t *certreq_payload_create(payload_type_t type) { private_certreq_payload_t *this; @@ -240,6 +263,7 @@ certreq_payload_t *certreq_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -250,9 +274,11 @@ certreq_payload_t *certreq_payload_create() .get_cert_type = _get_cert_type, .add_keyid = _add_keyid, .destroy = _destroy, + .get_dn = _get_dn, }, .next_payload = NO_PAYLOAD, - .payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -262,8 +288,10 @@ certreq_payload_t *certreq_payload_create() */ certreq_payload_t *certreq_payload_create_type(certificate_type_t type) { - private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(); + private_certreq_payload_t *this; + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST); switch (type) { case CERT_X509: @@ -278,3 +306,19 @@ certreq_payload_t *certreq_payload_create_type(certificate_type_t type) return &this->public; } +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id) +{ + private_certreq_payload_t *this; + + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST_V1); + + this->encoding = ENC_X509_SIGNATURE; + this->data = chunk_clone(id->get_encoding(id)); + this->payload_length = get_header_length(this) + this->data.len; + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index 914063628..cce71c0ad 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -27,25 +27,20 @@ typedef struct certreq_payload_t certreq_payload_t; #include #include #include +#include /** - * Length of a CERTREQ payload without the CERTREQ data in bytes. - */ -#define CERTREQ_PAYLOAD_HEADER_LENGTH 5 - -/** - * Class representing an IKEv2 CERTREQ payload. - * - * The CERTREQ payload format is described in RFC section 3.7. + * Class representing an IKEv1/IKEv2 CERTREQ payload. */ struct certreq_payload_t { + /** * The payload_t interface. */ payload_t payload_interface; /** - * Create an enumerator over contained keyids. + * Create an enumerator over contained keyids (IKEv2 only). * * @return enumerator over chunk_t's. */ @@ -59,13 +54,20 @@ struct certreq_payload_t { certificate_type_t (*get_cert_type)(certreq_payload_t *this); /** - * Add a certificates keyid to the payload. + * Add a certificates keyid to the payload (IKEv2 only). * * @param keyid keyid of the trusted certifcate * @return */ void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); + /** + * Get the distinguished name of the payload (IKEv1 only). + * + * @return DN as identity, must be destroyed + */ + identification_t* (*get_dn)(certreq_payload_t *this); + /** * Destroys an certreq_payload_t object. */ @@ -77,14 +79,22 @@ struct certreq_payload_t { * * @return certreq payload */ -certreq_payload_t *certreq_payload_create(void); +certreq_payload_t *certreq_payload_create(payload_type_t payload_type); /** - * Creates an empty certreq_payload_t for a kind of certificates. + * Creates an empty IKEv2 certreq_payload_t for a kind of certificates. * * @param type type of the added keyids * @return certreq payload */ certreq_payload_t *certreq_payload_create_type(certificate_type_t type); +/** + * Creates a IKEv1 certreq_payload_t for a given distinguished name. + * + * @param id distinguished name, does not get owned + * @return certreq payload + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id); + #endif /** CERTREQ_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index e608497bd..482eca882 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -36,41 +36,48 @@ struct private_configuration_attribute_t { configuration_attribute_t public; /** - * Reserved bit + * Value encoded in length field? + */ + bool af_flag; + + /** + * Reserved bit (af_flag in IKEv2) */ bool reserved; /** * Type of the attribute. */ - u_int16_t type; + u_int16_t attr_type; /** - * Length of the attribute. + * Length of the attribute, value if af_flag set. */ - u_int16_t length; + u_int16_t length_or_value; /** * Attribute value as chunk. */ chunk_t value; + + /** + * Payload type, CONFIGURATION_ATTRIBUTE or DATA_ATTRIBUTE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a configuration attribute. - * - * The defined offsets are the positions in a object of type - * private_configuration_attribute_t. + * Encoding rules for a IKEv2 configuration attribute / IKEv1 data attribute */ -encoding_rule_t configuration_attribute_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 reserved bit */ - { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved)}, + { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ - { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) }, + { ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ - { CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) } + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, }; /* @@ -85,87 +92,142 @@ encoding_rule_t configuration_attribute_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for a IKEv1 data attribute + */ +static encoding_rule_t encodings_v1[] = { + /* AF Flag */ + { ATTRIBUTE_FORMAT, offsetof(private_configuration_attribute_t, af_flag) }, + /* type of the attribute as 15 bit unsigned integer */ + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, + /* Length of attribute value */ + { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)}, + /* Value of attribute if attribute format flag is zero */ + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !F| Attribute Type ! Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Value ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_configuration_attribute_t *this) { bool failed = FALSE; - if (this->length != this->value.len) - { - DBG1(DBG_ENC, "invalid attribute length"); - return FAILED; - } - - switch (this->type) + switch (this->attr_type) { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (this->length != 0 && this->length != 4) + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 4) { failed = TRUE; } break; - case INTERNAL_IP4_SUBNET: - if (this->length != 0 && this->length != 8) + case INTERNAL_IP4_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 8) { failed = TRUE; } break; - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_SUBNET: - if (this->length != 0 && this->length != 17) + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 17) { failed = TRUE; } break; - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (this->length != 0 && this->length != 16) + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 16) { failed = TRUE; } break; - case SUPPORTED_ATTRIBUTES: - if (this->length % 2) + case SUPPORTED_ATTRIBUTES: + if (this->length_or_value % 2) { failed = TRUE; } break; - case APPLICATION_VERSION: + case APPLICATION_VERSION: + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + case XAUTH_TYPE: + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_STATUS: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + case UNITY_BANNER: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_LOCAL_LAN: + case UNITY_PFS: + case UNITY_FW_TYPE: + case UNITY_BACKUP_SERVERS: + case UNITY_DDNS_HOSTNAME: /* any length acceptable */ break; - default: + default: DBG1(DBG_ENC, "unknown attribute type %N", - configuration_attribute_type_names, this->type); + configuration_attribute_type_names, this->attr_type); break; } if (failed) { DBG1(DBG_ENC, "invalid attribute length %d for %N", - this->length, configuration_attribute_type_names, this->type); + this->length_or_value, configuration_attribute_type_names, + this->attr_type); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_configuration_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_configuration_attribute_t *this, encoding_rule_t **rules) +{ + if (this->type == CONFIGURATION_ATTRIBUTE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_configuration_attribute_t *this) { - *rules = configuration_attribute_encodings; - *rule_count = countof(configuration_attribute_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_configuration_attribute_t *this) { - return CONFIGURATION_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -182,21 +244,35 @@ METHOD(payload_t, set_next_type, void, METHOD(payload_t, get_length, size_t, private_configuration_attribute_t *this) { - return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; + return get_header_length(this) + this->value.len; } METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t, private_configuration_attribute_t *this) { - return this->type; + return this->attr_type; } -METHOD(configuration_attribute_t, get_value, chunk_t, +METHOD(configuration_attribute_t, get_chunk, chunk_t, private_configuration_attribute_t *this) { + if (this->af_flag) + { + return chunk_from_thing(this->length_or_value); + } return this->value; } +METHOD(configuration_attribute_t, get_value, u_int16_t, + private_configuration_attribute_t *this) +{ + if (this->af_flag) + { + return this->length_or_value; + } + return 0; +} + METHOD2(payload_t, configuration_attribute_t, destroy, void, private_configuration_attribute_t *this) { @@ -207,7 +283,7 @@ METHOD2(payload_t, configuration_attribute_t, destroy, void, /* * Described in header. */ -configuration_attribute_t *configuration_attribute_create() +configuration_attribute_t *configuration_attribute_create(payload_type_t type) { private_configuration_attribute_t *this; @@ -216,32 +292,53 @@ configuration_attribute_t *configuration_attribute_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, + .get_chunk = _get_chunk, .get_value = _get_value, .get_type = _get_cattr_type, .destroy = _destroy, }, + .type = type ); return &this->public; } +/* + * Described in header. + */ +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk) +{ + private_configuration_attribute_t *this; + + this = (private_configuration_attribute_t*) + configuration_attribute_create(type); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->value = chunk_clone(chunk); + this->length_or_value = chunk.len; + + return &this->public; +} + /* * Described in header. */ configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value) + configuration_attribute_type_t attr_type, u_int16_t value) { private_configuration_attribute_t *this; - this = (private_configuration_attribute_t*)configuration_attribute_create(); - this->type = ((u_int16_t)type) & 0x7FFF; - this->value = chunk_clone(value); - this->length = value.len; + this = (private_configuration_attribute_t*) + configuration_attribute_create(CONFIGURATION_ATTRIBUTE_V1); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->length_or_value = value; + this->af_flag = TRUE; return &this->public; } diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h index 6e4b018bb..ecc0f9c07 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.h +++ b/src/libcharon/encoding/payloads/configuration_attribute.h @@ -29,14 +29,7 @@ typedef struct configuration_attribute_t configuration_attribute_t; #include /** - * Configuration attribute header length in bytes. - */ -#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2-CONFIGURATION Attribute. - * - * The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1. + * Class representing an IKEv2 configuration attribute / IKEv1 data attribute. */ struct configuration_attribute_t { @@ -53,11 +46,18 @@ struct configuration_attribute_t { configuration_attribute_type_t (*get_type)(configuration_attribute_t *this); /** - * Returns the value of the attribute. + * Returns the value of the attribute as chunk. * * @return chunk_t pointing to the internal value */ - chunk_t (*get_value) (configuration_attribute_t *this); + chunk_t (*get_chunk) (configuration_attribute_t *this); + + /** + * Returns the 2 byte value of the attribute as u_int16. + * + * @return attribute value + */ + u_int16_t (*get_value) (configuration_attribute_t *this); /** * Destroys an configuration_attribute_t object. @@ -68,18 +68,30 @@ struct configuration_attribute_t { /** * Creates an empty configuration attribute. * - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @return created configuration attribute */ -configuration_attribute_t *configuration_attribute_create(); +configuration_attribute_t *configuration_attribute_create(payload_type_t type); /** * Creates a configuration attribute with type and value. * - * @param type type of configuration attribute - * @param value value, gets cloned - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @param attr_type type of configuration attribute + * @param chunk attribute value, gets cloned + * @return created configuration attribute + */ +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk); + +/** + * Creates a IKEv1 configuration attribute with 2 bytes value (IKEv1 only). + * + * @param attr_type type of configuration attribute + * @param value attribute value, gets cloned + * @return created CONFIGURATION_ATTRIBUTE_V1 configuration attribute */ configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value); + configuration_attribute_type_t attr_type, u_int16_t value); #endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 82e9e51b7..40f6ae48f 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -44,7 +44,7 @@ struct private_cp_payload_t { /** * Next payload type. */ - u_int8_t next_payload; + u_int8_t next_payload; /** * Critical flag. @@ -66,6 +66,11 @@ struct private_cp_payload_t { */ u_int16_t payload_length; + /** + * Identifier field, IKEv1 only + */ + u_int16_t identifier; + /** * List of attributes, as configuration_attribute_t */ @@ -74,38 +79,40 @@ struct private_cp_payload_t { /** * Config Type. */ - u_int8_t type; + u_int8_t cfg_type; + + /** + * CONFIGURATION or CONFIGURATION_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-CP Payload - * - * The defined offsets are the positions in a object of type - * private_cp_payload_t. + * Encoding rules to for an IKEv2 configuration payload */ -encoding_rule_t cp_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_cp_payload_t, critical) }, + { FLAG, offsetof(private_cp_payload_t, critical) }, /* 7 Bit reserved bits */ - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, /* Length of the whole CP payload*/ - { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { U_INT_8, offsetof(private_cp_payload_t, type) }, + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, /* 3 reserved bytes */ - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, - { CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) } + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, + offsetof(private_cp_payload_t, attributes) }, }; /* @@ -122,6 +129,47 @@ encoding_rule_t cp_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to for an IKEv1 configuration payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_cp_payload_t, critical) }, + /* 7 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + /* Length of the whole CP payload*/ + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, + /* 1 reserved bytes */ + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { U_INT_16, offsetof(private_cp_payload_t, identifier)}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1, + offsetof(private_cp_payload_t, attributes) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! CFG Type ! RESERVED ! Identifier ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Configuration Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_cp_payload_t *this) { @@ -142,17 +190,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_cp_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cp_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == CONFIGURATION) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_cp_payload_t *this) { - *rules = cp_payload_encodings; - *rule_count = countof(cp_payload_encodings); + return 8; } METHOD(payload_t, get_type, payload_type_t, private_cp_payload_t *this) { - return CONFIGURATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -175,7 +234,7 @@ static void compute_length(private_cp_payload_t *this) enumerator_t *enumerator; payload_t *attribute; - this->payload_length = CP_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) @@ -207,7 +266,18 @@ METHOD(cp_payload_t, add_attribute, void, METHOD(cp_payload_t, get_config_type, config_type_t, private_cp_payload_t *this) { - return this->type; + return this->cfg_type; +} + +METHOD(cp_payload_t, get_identifier, u_int16_t, + private_cp_payload_t *this) +{ + return this->identifier; +} +METHOD(cp_payload_t, set_identifier, void, + private_cp_payload_t *this, u_int16_t identifier) +{ + this->identifier = identifier; } METHOD2(payload_t, cp_payload_t, destroy, void, @@ -221,7 +291,7 @@ METHOD2(payload_t, cp_payload_t, destroy, void, /* * Described in header. */ -cp_payload_t *cp_payload_create_type(config_type_t type) +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type) { private_cp_payload_t *this; @@ -230,6 +300,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -239,11 +310,14 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .create_attribute_enumerator = _create_attribute_enumerator, .add_attribute = _add_attribute, .get_type = _get_config_type, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .attributes = linked_list_create(), + .cfg_type = cfg_type, .type = type, ); return &this->public; @@ -252,7 +326,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) /* * Described in header. */ -cp_payload_t *cp_payload_create() +cp_payload_t *cp_payload_create(payload_type_t type) { - return cp_payload_create_type(CFG_REQUEST); + return cp_payload_create_type(type, CFG_REQUEST); } diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h index afae6091a..5eb1e06a7 100644 --- a/src/libcharon/encoding/payloads/cp_payload.h +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -30,11 +30,6 @@ typedef struct cp_payload_t cp_payload_t; #include #include -/** - * CP_PAYLOAD length in bytes without any proposal substructure. - */ -#define CP_PAYLOAD_HEADER_LENGTH 8 - /** * Config Type of an Configuration Payload. */ @@ -51,9 +46,7 @@ enum config_type_t { extern enum_name_t *config_type_names; /** - * Class representing an IKEv2-CP Payload. - * - * The CP Payload format is described in RFC section 3.15. + * Class representing an IKEv2 configuration / IKEv1 attribute payload. */ struct cp_payload_t { @@ -84,6 +77,20 @@ struct cp_payload_t { */ config_type_t (*get_type) (cp_payload_t *this); + /** + * Set the configuration payload identifier (IKEv1 only). + * + @param identifier identifier to set + */ + void (*set_identifier) (cp_payload_t *this, u_int16_t identifier); + + /** + * Get the configuration payload identifier (IKEv1 only). + * + * @return identifier + */ + u_int16_t (*get_identifier) (cp_payload_t *this); + /** * Destroys an cp_payload_t object. */ @@ -93,16 +100,18 @@ struct cp_payload_t { /** * Creates an empty configuration payload * - * @return empty configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @return empty configuration payload */ -cp_payload_t *cp_payload_create(); +cp_payload_t *cp_payload_create(payload_type_t type); /** * Creates an cp_payload_t with type and value * - * @param config_type type of configuration payload to create - * @return created configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @param cfg_type type of configuration payload to create + * @return created configuration payload */ -cp_payload_t *cp_payload_create_type(config_type_t config_type); +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type); #endif /** CP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index e6ee07d39..007411f37 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -24,9 +24,9 @@ typedef struct private_delete_payload_t private_delete_payload_t; /** * Private data of an delete_payload_t object. - * */ struct private_delete_payload_t { + /** * Public delete_payload_t interface. */ @@ -45,13 +45,18 @@ struct private_delete_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. */ u_int16_t payload_length; + /** + * IKEv1 Domain of Interpretation + */ + u_int32_t doi; + /** * Protocol ID. */ @@ -71,19 +76,21 @@ struct private_delete_payload_t { * The contained SPI's. */ chunk_t spis; + + /** + * Payload type, DELETE or DELETE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a DELETE payload - * - * The defined offsets are the positions in a object of type - * private_delete_payload_t. + * Encoding rules for an IKEv2 delete payload. */ -encoding_rule_t delete_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_delete_payload_t, critical) }, + { FLAG, offsetof(private_delete_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, @@ -98,7 +105,47 @@ encoding_rule_t delete_payload_encodings[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { SPIS, offsetof(private_delete_payload_t, spis) } + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! # of SPIs ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index(es) (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for an IKEv1 delete payload. + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + /* 8 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) }, + /* Domain of interpretation */ + { U_INT_32, offsetof(private_delete_payload_t, doi) }, + { U_INT_8, offsetof(private_delete_payload_t, protocol_id) }, + { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, + { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, + /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, }; /* @@ -107,6 +154,8 @@ encoding_rule_t delete_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload !C! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Protocol ID ! SPI Size ! # of SPIs ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! @@ -129,10 +178,19 @@ METHOD(payload_t, verify, status_t, break; case PROTO_IKE: case 0: - /* IKE deletion has no spi assigned! */ - if (this->spi_size != 0) - { - return FAILED; + if (this->type == DELETE) + { /* IKEv2 deletion has no spi assigned! */ + if (this->spi_size != 0) + { + return FAILED; + } + } + else + { /* IKEv1 uses the two concatenated ISAKMP cookies as SPI */ + if (this->spi_size != 16) + { + return FAILED; + } } break; default: @@ -145,17 +203,32 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_delete_payload_t *this, encoding_rule_t **rules) { - *rules = delete_payload_encodings; - *rule_count = countof(delete_payload_encodings); + if (this->type == DELETE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_delete_payload_t *this) +{ + if (this->type == DELETE) + { + return 8; + } + return 12; } METHOD(payload_t, get_payload_type, payload_type_t, private_delete_payload_t *this) { - return DELETE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -198,6 +271,16 @@ METHOD(delete_payload_t, add_spi, void, } } +METHOD(delete_payload_t, set_ike_spi, void, + private_delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r) +{ + free(this->spis.ptr); + this->spis = chunk_cat("cc", chunk_from_thing(spi_i), + chunk_from_thing(spi_r)); + this->spi_count = 1; + this->payload_length = get_header_length(this) + this->spi_size; +} + /** * SPI enumerator implementation */ @@ -249,7 +332,8 @@ METHOD2(payload_t, delete_payload_t, destroy, void, /* * Described in header */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id) +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id) { private_delete_payload_t *this; @@ -258,6 +342,7 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -266,13 +351,27 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) }, .get_protocol_id = _get_protocol_id, .add_spi = _add_spi, + .set_ike_spi = _set_ike_spi, .create_spi_enumerator = _create_spi_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = DELETE_PAYLOAD_HEADER_LENGTH, .protocol_id = protocol_id, - .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, + .doi = IKEV1_DOI_IPSEC, + .type = type, ); + this->payload_length = get_header_length(this); + + if (protocol_id == PROTO_IKE) + { + if (type == DELETE_V1) + { + this->spi_size = 16; + } + } + else + { + this->spi_size = 4; + } return &this->public; } diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index 026829f97..afce1ecf1 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -29,14 +29,7 @@ typedef struct delete_payload_t delete_payload_t; #include /** - * Length of a delete payload without the SPI in bytes. - */ -#define DELETE_PAYLOAD_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2 DELETE payload. - * - * The DELETE payload format is described in RFC section 3.11. + * Class representing an IKEv1 or a IKEv2 DELETE payload. */ struct delete_payload_t { @@ -59,6 +52,14 @@ struct delete_payload_t { */ void (*add_spi) (delete_payload_t *this, u_int32_t spi); + /** + * Set the IKE SPIs for an IKEv1 delete. + * + * @param spi_i initiator SPI + * @param spi_r responder SPI + */ + void (*set_ike_spi)(delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r); + /** * Get an enumerator over the SPIs in network order. * @@ -75,9 +76,11 @@ struct delete_payload_t { /** * Creates an empty delete_payload_t object. * + * @param type DELETE or DELETE_V1 * @param protocol_id protocol, such as AH|ESP * @return delete_payload_t object */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id); +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id); #endif /** DELETE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index cacaef222..dd2e25795 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -19,6 +20,8 @@ #include "eap_payload.h" #include +#include +#include typedef struct private_eap_payload_t private_eap_payload_t; @@ -65,7 +68,7 @@ struct private_eap_payload_t { * private_eap_payload_t. * */ -static encoding_rule_t eap_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_eap_payload_t, next_payload) }, /* the critical bit */ @@ -81,7 +84,7 @@ static encoding_rule_t eap_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) }, /* chunt to data, starting at "code" */ - { EAP_DATA, offsetof(private_eap_payload_t, data) }, + { CHUNK_DATA, offsetof(private_eap_payload_t, data) }, }; /* @@ -143,11 +146,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_eap_payload_t *this, encoding_rule_t **rules) { - *rules = eap_payload_encodings; - *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_eap_payload_t *this) +{ + return 4; } METHOD(payload_t, get_payload_type, payload_type_t, @@ -210,28 +219,93 @@ METHOD(eap_payload_t, get_identifier, u_int8_t, return 0; } +/** + * Get the current type at the given offset into this->data. + * @return the new offset or 0 if failed + */ +static size_t extract_type(private_eap_payload_t *this, size_t offset, + eap_type_t *type, u_int32_t *vendor) +{ + if (this->data.len > offset) + { + *vendor = 0; + *type = this->data.ptr[offset]; + if (*type != EAP_EXPANDED) + { + return offset + 1; + } + if (this->data.len >= offset + 8) + { + *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF; + *type = untoh32(this->data.ptr + offset + 4); + return offset + 8; + } + } + return 0; +} + METHOD(eap_payload_t, get_type, eap_type_t, private_eap_payload_t *this, u_int32_t *vendor) { eap_type_t type; *vendor = 0; - if (this->data.len > 4) + if (extract_type(this, 4, &type, vendor)) { - type = this->data.ptr[4]; - if (type != EAP_EXPANDED) - { - return type; - } - if (this->data.len >= 12) - { - *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF; - return untoh32(this->data.ptr + 8); - } + return type; } return 0; } +/** + * Type enumerator + */ +typedef struct { + /** public interface */ + enumerator_t public; + /** payload */ + private_eap_payload_t *payload; + /** current offset in the data */ + size_t offset; +} type_enumerator_t; + +METHOD(enumerator_t, enumerate_types, bool, + type_enumerator_t *this, eap_type_t *type, u_int32_t *vendor) +{ + this->offset = extract_type(this->payload, this->offset, type, vendor); + return this->offset; +} + +METHOD(eap_payload_t, get_types, enumerator_t*, + private_eap_payload_t *this) +{ + type_enumerator_t *enumerator; + eap_type_t type; + u_int32_t vendor; + size_t offset; + + offset = extract_type(this, 4, &type, &vendor); + if (offset && type == EAP_NAK) + { + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_types, + .destroy = (void*)free, + }, + .payload = this, + .offset = offset, + ); + return &enumerator->public; + } + return enumerator_create_empty(); +} + +METHOD(eap_payload_t, is_expanded, bool, + private_eap_payload_t *this) +{ + return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE; +} + METHOD2(payload_t, eap_payload_t, destroy, void, private_eap_payload_t *this) { @@ -251,6 +325,7 @@ eap_payload_t *eap_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -262,10 +337,12 @@ eap_payload_t *eap_payload_create() .get_code = _get_code, .get_identifier = _get_identifier, .get_type = _get_type, + .get_types = _get_types, + .is_expanded = _is_expanded, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = EAP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } @@ -305,15 +382,81 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier) return eap_payload_create_data(data); } +/** + * Write the given type either expanded or not + */ +static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor, + bool expanded) +{ + if (expanded) + { + writer->write_uint8(writer, EAP_EXPANDED); + writer->write_uint24(writer, vendor); + writer->write_uint32(writer, type); + } + else + { + writer->write_uint8(writer, type); + } +} + /* * Described in header */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier) +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded) { - chunk_t data; + enumerator_t *enumerator; + eap_type_t reg_type; + u_int32_t reg_vendor; + bio_writer_t *writer; + chunk_t length, data; + bool added_any = FALSE, found_vendor = FALSE; + eap_payload_t *payload; + + writer = bio_writer_create(12); + writer->write_uint8(writer, EAP_RESPONSE); + writer->write_uint8(writer, identifier); + length = writer->skip(writer, 2); + + write_type(writer, EAP_NAK, 0, expanded); + + enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER); + while (enumerator->enumerate(enumerator, ®_type, ®_vendor)) + { + if ((type && type != reg_type) || + (type && vendor && vendor != reg_vendor)) + { /* the preferred type is only sent if we actually find it */ + continue; + } + if (!reg_vendor || expanded) + { + write_type(writer, reg_type, reg_vendor, expanded); + added_any = TRUE; + } + else if (reg_vendor) + { /* found vendor specifc method, but this is not an expanded Nak */ + found_vendor = TRUE; + } + } + enumerator->destroy(enumerator); - data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK); - htoun16(data.ptr + 2, data.len); - return eap_payload_create_data(data); + if (found_vendor) + { /* request an expanded authentication type */ + write_type(writer, EAP_EXPANDED, 0, expanded); + added_any = TRUE; + } + if (!added_any) + { /* no methods added */ + write_type(writer, 0, 0, expanded); + } + + /* set length */ + data = writer->get_buf(writer); + htoun16(length.ptr, data.len); + + payload = eap_payload_create_data(data); + writer->destroy(writer); + return payload; } diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index 60d9c99d2..e8ed1c5e7 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,13 +26,8 @@ typedef struct eap_payload_t eap_payload_t; #include +#include #include -#include - -/** - * Length of a EAP payload without the EAP Message in bytes. - */ -#define EAP_PAYLOAD_HEADER_LENGTH 4 /** * Class representing an IKEv2 EAP payload. @@ -86,6 +82,21 @@ struct eap_payload_t { */ eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); + /** + * Enumerate the EAP method types contained in an EAP-Nak (i.e. get_type() + * returns EAP_NAK). + * + * @return enumerator over (eap_type_t type, u_int32_t vendor) + */ + enumerator_t* (*get_types) (eap_payload_t *this); + + /** + * Check if the EAP method type is encoded in the Expanded Type format. + * + * @return TRUE if in Expanded Type format + */ + bool (*is_expanded) (eap_payload_t *this); + /** * Destroys an eap_payload_t object. */ @@ -131,8 +142,12 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. * * @param identifier EAP identifier to use in payload + * @param type preferred auth type, 0 to send all supported types + * @param vendor vendor identifier for auth type, 0 for default + * @param expanded TRUE to send an expanded Nak * @return eap_payload_t object */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier); +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded); #endif /** EAP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 85caeda82..62de81120 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -29,30 +29,14 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "HEADER_LENGTH", "SPI_SIZE", "SPI", - "KEY_EXCHANGE_DATA", - "NOTIFICATION_DATA", - "PROPOSALS", - "TRANSFORMS", - "TRANSFORM_ATTRIBUTES", - "CONFIGURATION_ATTRIBUTES", - "CONFIGURATION_ATTRIBUTE_VALUE", "ATTRIBUTE_FORMAT", "ATTRIBUTE_TYPE", "ATTRIBUTE_LENGTH_OR_VALUE", - "CONFIGURATION_ATTRIBUTE_LENGTH", + "ATTRIBUTE_LENGTH", "ATTRIBUTE_VALUE", - "TRAFFIC_SELECTORS", "TS_TYPE", "ADDRESS", - "NONCE_DATA", - "ID_DATA", - "AUTH_DATA", - "CERT_DATA", - "CERTREQ_DATA", - "EAP_DATA", - "SPIS", - "VID_DATA", - "UNKNOWN_DATA", + "CHUNK_DATA", "IKE_SPI", "ENCRYPTED_DATA", ); diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 52af4a984..54830bc8c 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -186,87 +186,6 @@ enum encoding_type_t { */ SPI, - /** - * Representating a Key Exchange Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - KEY_EXCHANGE_DATA, - - /** - * Representating a Notification field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to. - */ - NOTIFICATION_DATA, - - /** - * Representating one or more proposal substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the proposal_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed proposal_substructure_t objects have - * to be stored in the pointed linked_list. - */ - PROPOSALS, - - /** - * Representating one or more transform substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORMS, - - /** - * Representating one or more Attributes of a transform substructure. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_attribute_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORM_ATTRIBUTES, - - /** - * Representating one or more Attributes of a configuration payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the configuration_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed configuration_attribute_t objects have - * to be stored in the pointed linked_list. - */ - CONFIGURATION_ATTRIBUTES, - - /** - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - CONFIGURATION_ATTRIBUTE_VALUE, - /** * Representing a 1 Bit flag specifying the format of a transform attribute. * @@ -279,6 +198,7 @@ enum encoding_type_t { * is moved 1 bit forward afterwards. */ ATTRIBUTE_FORMAT, + /** * Representing a 15 Bit unsigned int value used as attribute type * in an attribute transform. @@ -321,7 +241,7 @@ enum encoding_type_t { * The value is written to the associated data struct. * The current read pointer is moved 16 bit forward afterwards. */ - CONFIGURATION_ATTRIBUTE_LENGTH, + ATTRIBUTE_LENGTH, /** * Depending on the field of type ATTRIBUTE_FORMAT @@ -335,19 +255,6 @@ enum encoding_type_t { */ ATTRIBUTE_VALUE, - /** - * Representating one or more Traffic selectors of a TS payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the traffic_selector_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed traffic_selector_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRAFFIC_SELECTORS, - /** * Representating a Traffic selector type field. * @@ -375,94 +282,9 @@ enum encoding_type_t { ADDRESS, /** - * Representating a Nonce Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. + * Representing a variable length byte field. */ - NONCE_DATA, - - /** - * Representating a ID Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - ID_DATA, - - /** - * Representating a AUTH Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - AUTH_DATA, - - /** - * Representating a CERT Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERT_DATA, - - /** - * Representating a CERTREQ Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERTREQ_DATA, - - /** - * Representating an EAP message field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - EAP_DATA, - - /** - * Representating the SPIS field in a DELETE payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - SPIS, - - /** - * Representating the VID DATA field in a VENDOR ID payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - VID_DATA, - - /** - * Representating the DATA of an unknown payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - UNKNOWN_DATA, + CHUNK_DATA, /** * Representating an IKE_SPI field in an IKEv2 Header. @@ -475,9 +297,20 @@ enum encoding_type_t { IKE_SPI, /** - * Representing the encrypted data body of a encryption payload. + * Representating an encrypted IKEv1 message. */ ENCRYPTED_DATA, + + /** + * Reprensenting a field containing a set of wrapped payloads. + * + * This type is not used directly, but as an offset to the wrapped payloads. + * The type of the wrapped payload is added to this encoding type. + * + * @note As payload types are added to this encoding type, it has + * to be the last in encoding_type_t. + */ + PAYLOAD_LIST = 1000 /* no comma, read above! */ }; /** diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index e7b8063b7..02e7b8bf3 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -71,6 +72,11 @@ struct private_encryption_payload_t { * Contained payloads */ linked_list_t *payloads; + + /** + * Type of payload, ENCRYPTED or ENCRYPTED_V1 + */ + payload_type_t type; }; /** @@ -79,7 +85,7 @@ struct private_encryption_payload_t { * The defined offsets are the positions in a object of type * private_encryption_payload_t. */ -encoding_rule_t encryption_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, /* Critical and 7 reserved bits, all stored for reconstruction */ @@ -87,7 +93,7 @@ encoding_rule_t encryption_payload_encodings[] = { /* Length of the whole encryption payload*/ { PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) }, /* encrypted data, stored in a chunk. contains iv, data, padding */ - { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, + { CHUNK_DATA, offsetof(private_encryption_payload_t, encrypted) }, }; /* @@ -109,24 +115,59 @@ encoding_rule_t encryption_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to parse or generate a complete encrypted IKEv1 message. + * + * The defined offsets are the positions in a object of type + * private_encryption_payload_t. + */ +static encoding_rule_t encodings_v1[] = { + /* encrypted data, stored in a chunk */ + { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Encrypted IKE Payloads ! + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! Padding (0-255 octets) ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_encryption_payload_t *this) { return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_encryption_payload_t *this, encoding_rule_t **rules, - size_t *count) +METHOD(payload_t, get_encoding_rules, int, + private_encryption_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == ENCRYPTED) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_encryption_payload_t *this) { - *rules = encryption_payload_encodings; - *count = countof(encryption_payload_encodings); + if (this->type == ENCRYPTED) + { + return 4; + } + return 0; } METHOD(payload_t, get_type, payload_type_t, private_encryption_payload_t *this) { - return ENCRYPTED; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -138,7 +179,8 @@ METHOD(payload_t, get_next_type, payload_type_t, METHOD(payload_t, set_next_type, void, private_encryption_payload_t *this, payload_type_t type) { - /* the next payload is set during add */ + /* the next payload is set during add, still allow this for IKEv1 */ + this->next_payload = type; } /** @@ -174,7 +216,7 @@ static void compute_length(private_encryption_payload_t *this) length += this->aead->get_icv_size(this->aead); } } - length += ENCRYPTION_PAYLOAD_HEADER_LENGTH; + length += get_header_length(this); this->payload_length = length; } @@ -266,7 +308,7 @@ static chunk_t append_header(private_encryption_payload_t *this, chunk_t assoc) return chunk_cat("cc", assoc, chunk_from_thing(header)); } -METHOD(encryption_payload_t, encrypt, bool, +METHOD(encryption_payload_t, encrypt, status_t, private_encryption_payload_t *this, chunk_t assoc) { chunk_t iv, plain, padding, icv, crypt; @@ -277,14 +319,14 @@ METHOD(encryption_payload_t, encrypt, bool, if (this->aead == NULL) { DBG1(DBG_ENC, "encrypting encryption payload failed, transform missing"); - return FALSE; + return INVALID_STATE; } rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!rng) { DBG1(DBG_ENC, "encrypting encryption payload failed, no RNG found"); - return FALSE; + return NOT_SUPPORTED; } assoc = append_header(this, assoc); @@ -314,8 +356,14 @@ METHOD(encryption_payload_t, encrypt, bool, crypt = chunk_create(plain.ptr, plain.len + padding.len); generator->destroy(generator); - rng->get_bytes(rng, iv.len, iv.ptr); - rng->get_bytes(rng, padding.len - 1, padding.ptr); + if (!rng->get_bytes(rng, iv.len, iv.ptr) || + !rng->get_bytes(rng, padding.len - 1, padding.ptr)) + { + DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding"); + rng->destroy(rng); + free(assoc.ptr); + return FAILED; + } padding.ptr[padding.len - 1] = padding.len - 1; rng->destroy(rng); @@ -325,14 +373,60 @@ METHOD(encryption_payload_t, encrypt, bool, DBG3(DBG_ENC, "padding %B", &padding); DBG3(DBG_ENC, "assoc %B", &assoc); - this->aead->encrypt(this->aead, crypt, assoc, iv, NULL); + if (!this->aead->encrypt(this->aead, crypt, assoc, iv, NULL)) + { + free(assoc.ptr); + return FAILED; + } DBG3(DBG_ENC, "encrypted %B", &crypt); DBG3(DBG_ENC, "ICV %B", &icv); free(assoc.ptr); - return TRUE; + return SUCCESS; +} + +METHOD(encryption_payload_t, encrypt_v1, status_t, + private_encryption_payload_t *this, chunk_t iv) +{ + generator_t *generator; + chunk_t plain, padding; + size_t bs; + + if (this->aead == NULL) + { + DBG1(DBG_ENC, "encryption failed, transform missing"); + return INVALID_STATE; + } + + generator = generator_create(); + plain = generate(this, generator); + bs = this->aead->get_block_size(this->aead); + padding.len = bs - (plain.len % bs); + + /* prepare data to encrypt: + * | plain | padding | */ + free(this->encrypted.ptr); + this->encrypted = chunk_alloc(plain.len + padding.len); + memcpy(this->encrypted.ptr, plain.ptr, plain.len); + plain.ptr = this->encrypted.ptr; + padding.ptr = plain.ptr + plain.len; + memset(padding.ptr, 0, padding.len); + generator->destroy(generator); + + DBG3(DBG_ENC, "encrypting payloads:"); + DBG3(DBG_ENC, "plain %B", &plain); + DBG3(DBG_ENC, "padding %B", &padding); + + if (!this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL)) + { + return FAILED; + } + + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + return SUCCESS; } /** @@ -349,6 +443,13 @@ static status_t parse(private_encryption_payload_t *this, chunk_t plain) { payload_t *payload; + if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len) + { + DBG1(DBG_ENC, "invalid %N payload length, decryption failed?", + payload_type_names, type); + parser->destroy(parser); + return PARSE_ERROR; + } if (parser->parse_payload(parser, type, &payload) != SUCCESS) { parser->destroy(parser); @@ -438,6 +539,36 @@ METHOD(encryption_payload_t, decrypt, status_t, return parse(this, plain); } +METHOD(encryption_payload_t, decrypt_v1, status_t, + private_encryption_payload_t *this, chunk_t iv) +{ + if (this->aead == NULL) + { + DBG1(DBG_ENC, "decryption failed, transform missing"); + return INVALID_STATE; + } + + /* data must be a multiple of block size */ + if (iv.len != this->aead->get_block_size(this->aead) || + this->encrypted.len < iv.len || this->encrypted.len % iv.len) + { + DBG1(DBG_ENC, "decryption failed, invalid length"); + return FAILED; + } + + DBG3(DBG_ENC, "decrypting payloads:"); + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + if (!this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL)) + { + return FAILED; + } + + DBG3(DBG_ENC, "plain %B", &this->encrypted); + + return parse(this, this->encrypted); +} + METHOD(encryption_payload_t, set_transform, void, private_encryption_payload_t *this, aead_t* aead) { @@ -455,7 +586,7 @@ METHOD2(payload_t, encryption_payload_t, destroy, void, /* * Described in header */ -encryption_payload_t *encryption_payload_create() +encryption_payload_t *encryption_payload_create(payload_type_t type) { private_encryption_payload_t *this; @@ -464,6 +595,7 @@ encryption_payload_t *encryption_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -479,9 +611,16 @@ encryption_payload_t *encryption_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH, .payloads = linked_list_create(), + .type = type, ); + this->payload_length = get_header_length(this); + + if (type == ENCRYPTED_V1) + { + this->public.encrypt = _encrypt_v1; + this->public.decrypt = _decrypt_v1; + } return &this->public; } diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h index e99c42fb7..5c6069339 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.h +++ b/src/libcharon/encoding/payloads/encryption_payload.h @@ -29,11 +29,6 @@ typedef struct encryption_payload_t encryption_payload_t; #include #include -/** - * Encrpytion payload length in bytes without IV and following data. - */ -#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 - /** * The encryption payload as described in RFC section 3.14. */ @@ -77,14 +72,18 @@ struct encryption_payload_t { * Generate, encrypt and sign contained payloads. * * @param assoc associated data - * @return TRUE if encrypted + * @return + * - SUCCESS if encryption successful + * - FAILED if encryption failed + * - INVALID_STATE if aead not supplied, but needed */ - bool (*encrypt) (encryption_payload_t *this, chunk_t assoc); + status_t (*encrypt) (encryption_payload_t *this, chunk_t assoc); /** * Decrypt, verify and parse contained payloads. * * @param assoc associated data + * @return * - SUCCESS if parsing successful * - PARSE_ERROR if sub-payload parsing failed * - VERIFY_ERROR if sub-payload verification failed @@ -102,8 +101,9 @@ struct encryption_payload_t { /** * Creates an empty encryption_payload_t object. * + * @param type ENCRYPTED or ENCRYPTED_V1 * @return encryption_payload_t object */ -encryption_payload_t *encryption_payload_create(void); +encryption_payload_t *encryption_payload_create(payload_type_t type); #endif /** ENCRYPTION_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c index 1ead0a052..25fb42acd 100644 --- a/src/libcharon/encoding/payloads/endpoint_notify.c +++ b/src/libcharon/encoding/payloads/endpoint_notify.c @@ -227,7 +227,7 @@ METHOD(endpoint_notify_t, build_notify, notify_payload_t*, chunk_t data; notify_payload_t *notify; - notify = notify_payload_create(); + notify = notify_payload_create(NOTIFY); notify->set_notify_type(notify, ME_ENDPOINT); data = build_notification_data(this); notify->set_notification_data(notify, data); diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c new file mode 100644 index 000000000..0cf63ba67 --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "hash_payload.h" + +#include + +typedef struct private_hash_payload_t private_hash_payload_t; + +/** + * Private data of an hash_payload_t object. + */ +struct private_hash_payload_t { + + /** + * Public hash_payload_t interface. + */ + hash_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Reserved byte + */ + u_int8_t reserved; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained hash value. + */ + chunk_t hash; + + /** + * either HASH_V1 or NAT_D_V1 + */ + payload_type_t type; +}; + +/** + * Encoding rules for an IKEv1 hash payload + */ +static encoding_rule_t encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_hash_payload_t, next_payload) }, + { RESERVED_BYTE, offsetof(private_hash_payload_t, reserved) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_hash_payload_t, payload_length) }, + /* Hash Data is from variable size */ + { CHUNK_DATA, offsetof(private_hash_payload_t, hash) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Hash Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_hash_payload_t *this) +{ + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, int, + private_hash_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_hash_payload_t *this) +{ + return 4; +} + +METHOD(payload_t, get_type, payload_type_t, + private_hash_payload_t *this) +{ + return this->type; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_hash_payload_t *this) +{ + return this->next_payload; +} + +METHOD(payload_t, set_next_type, void, + private_hash_payload_t *this, payload_type_t type) +{ + this->next_payload = type; +} + +METHOD(payload_t, get_length, size_t, + private_hash_payload_t *this) +{ + return this->payload_length; +} + +METHOD(hash_payload_t, set_hash, void, + private_hash_payload_t *this, chunk_t hash) +{ + free(this->hash.ptr); + this->hash = chunk_clone(hash); + this->payload_length = get_header_length(this) + hash.len; +} + +METHOD(hash_payload_t, get_hash, chunk_t, + private_hash_payload_t *this) +{ + return this->hash; +} + +METHOD2(payload_t, hash_payload_t, destroy, void, + private_hash_payload_t *this) +{ + free(this->hash.ptr); + free(this); +} + +/* + * Described in header + */ +hash_payload_t *hash_payload_create(payload_type_t type) +{ + private_hash_payload_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .set_hash = _set_hash, + .get_hash = _get_hash, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + .payload_length = get_header_length(this), + .type = type, + ); + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/hash_payload.h b/src/libcharon/encoding/payloads/hash_payload.h new file mode 100644 index 000000000..cfe28460c --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hash_payload hash_payload + * @{ @ingroup payloads + */ + +#ifndef HASH_PAYLOAD_H_ +#define HASH_PAYLOAD_H_ + +typedef struct hash_payload_t hash_payload_t; + +#include +#include + +/** + * Object representing an IKEv1 hash payload. + */ +struct hash_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the hash value. + * + * @param hash chunk containing the hash, will be cloned + */ + void (*set_hash) (hash_payload_t *this, chunk_t hash); + + /** + * Get the hash value. + * + * @return chunkt to internal hash data + */ + chunk_t (*get_hash) (hash_payload_t *this); + + /** + * Destroys an hash_payload_t object. + */ + void (*destroy) (hash_payload_t *this); +}; + +/** + * Creates an empty hash_payload_t object. + * + * @param type either HASH_V1 or NAT_D_V1 + * @return hash_payload_t object + */ +hash_payload_t *hash_payload_create(payload_type_t type); + +#endif /** HASH_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 3befadfe2..02b07d691 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -1,9 +1,8 @@ /* - * Copyright (C) 2005-2010 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2010 revosec AG - * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter - * * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,19 +27,14 @@ typedef struct private_id_payload_t private_id_payload_t; /** * Private data of an id_payload_t object. - * */ struct private_id_payload_t { + /** * Public id_payload_t interface. */ id_payload_t public; - /** - * one of ID_INITIATOR, ID_RESPONDER - */ - payload_type_t payload_type; - /** * Next payload type. */ @@ -75,19 +69,31 @@ struct private_id_payload_t { * The contained id data value. */ chunk_t id_data; + + /** + * Tunneled protocol ID for IKEv1 quick modes. + */ + u_int8_t protocol_id; + + /** + * Tunneled port for IKEv1 quick modes. + */ + u_int16_t port; + + /** + * one of ID_INITIATOR, ID_RESPONDER, IDv1 and NAT_OA_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a ID payload - * - * The defined offsets are the positions in a object of type - * private_id_payload_t. + * Encoding rules for an IKEv2 ID payload */ -encoding_rule_t id_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_id_payload_t, critical) }, + { FLAG, offsetof(private_id_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[0]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[1]) }, @@ -97,7 +103,7 @@ encoding_rule_t id_payload_encodings[] = { { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[5]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, /* 1 Byte ID type*/ { U_INT_8, offsetof(private_id_payload_t, id_type) }, /* 3 reserved bytes */ @@ -105,7 +111,7 @@ encoding_rule_t id_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[2])}, /* some id data bytes, length is defined in PAYLOAD_LENGTH */ - { ID_DATA, offsetof(private_id_payload_t, id_data) } + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, }; /* @@ -122,29 +128,92 @@ encoding_rule_t id_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 ID payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + /* 1 Byte ID type*/ + { U_INT_8, offsetof(private_id_payload_t, id_type) }, + { U_INT_8, offsetof(private_id_payload_t, protocol_id) }, + { U_INT_16, offsetof(private_id_payload_t, port) }, + /* some id data bytes, length is defined in PAYLOAD_LENGTH */ + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ID Type ! Protocol ID ! Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Identification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_id_payload_t *this) { - if (this->id_type == 0 || this->id_type == 4) + bool bad_length = FALSE; + + if (this->type == NAT_OA_V1 && + this->id_type != ID_IPV4_ADDR && this->id_type != ID_IPV6_ADDR) + { + DBG1(DBG_ENC, "invalid ID type %N for %N payload", id_type_names, + this->id_type, payload_type_short_names, this->type); + return FAILED; + } + switch (this->id_type) + { + case ID_IPV4_ADDR_RANGE: + case ID_IPV4_ADDR_SUBNET: + bad_length = this->id_data.len != 8; + break; + case ID_IPV6_ADDR_RANGE: + case ID_IPV6_ADDR_SUBNET: + bad_length = this->id_data.len != 32; + break; + } + if (bad_length) { - /* reserved IDs */ - DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type); + DBG1(DBG_ENC, "invalid %N length (%d bytes)", + id_type_names, this->id_type, this->id_data.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_id_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == ID_V1 || this->type == NAT_OA_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); +} + +METHOD(payload_t, get_header_length, int, + private_id_payload_t *this) { - *rules = id_payload_encodings; - *rule_count = countof(id_payload_encodings); + return 8; } METHOD(payload_t, get_type, payload_type_t, private_id_payload_t *this) { - return this->payload_type; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -171,6 +240,102 @@ METHOD(id_payload_t, get_identification, identification_t*, return identification_create_from_encoding(this->id_type, this->id_data); } +/** + * Create a traffic selector from an range ID + */ +static traffic_selector_t *get_ts_from_range(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + chunk_create(this->id_data.ptr, this->id_data.len / 2), this->port, + chunk_skip(this->id_data, this->id_data.len / 2), this->port ?: 65535); +} + +/** + * Create a traffic selector from an subnet ID + */ +static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this, + ts_type_t type) +{ + chunk_t net, netmask; + int i; + + net = chunk_create(this->id_data.ptr, this->id_data.len / 2); + netmask = chunk_skip(this->id_data, this->id_data.len / 2); + for (i = 0; i < net.len; i++) + { + netmask.ptr[i] = (netmask.ptr[i] ^ 0xFF) | net.ptr[i]; + } + return traffic_selector_create_from_bytes(this->protocol_id, type, + net, this->port, netmask, this->port ?: 65535); +} + +/** + * Create a traffic selector from an IP ID + */ +static traffic_selector_t *get_ts_from_ip(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + this->id_data, this->port, this->id_data, this->port ?: 65535); +} + +METHOD(id_payload_t, get_ts, traffic_selector_t*, + private_id_payload_t *this) +{ + switch (this->id_type) + { + case ID_IPV4_ADDR_SUBNET: + if (this->id_data.len == 8) + { + return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_SUBNET: + if (this->id_data.len == 32) + { + return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE); + } + break; + case ID_IPV4_ADDR_RANGE: + if (this->id_data.len == 8) + { + return get_ts_from_range(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_RANGE: + if (this->id_data.len == 32) + { + return get_ts_from_range(this, TS_IPV6_ADDR_RANGE); + } + break; + case ID_IPV4_ADDR: + if (this->id_data.len == 4) + { + return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR: + if (this->id_data.len == 16) + { + return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE); + } + break; + default: + break; + } + return NULL; +} + +METHOD(id_payload_t, get_encoded, chunk_t, + private_id_payload_t *this) +{ + u_int16_t port = htons(this->port); + return chunk_cat("cccc", chunk_from_thing(this->id_type), + chunk_from_thing(this->protocol_id), + chunk_from_thing(port), this->id_data); +} + METHOD2(payload_t, id_payload_t, destroy, void, private_id_payload_t *this) { @@ -181,7 +346,7 @@ METHOD2(payload_t, id_payload_t, destroy, void, /* * Described in header. */ -id_payload_t *id_payload_create(payload_type_t payload_type) +id_payload_t *id_payload_create(payload_type_t type) { private_id_payload_t *this; @@ -190,6 +355,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -197,11 +363,13 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .destroy = _destroy, }, .get_identification = _get_identification, + .get_encoded = _get_encoded, + .get_ts = _get_ts, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ID_PAYLOAD_HEADER_LENGTH, - .payload_type = payload_type, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -209,15 +377,89 @@ id_payload_t *id_payload_create(payload_type_t payload_type) /* * Described in header. */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, +id_payload_t *id_payload_create_from_identification(payload_type_t type, identification_t *id) { private_id_payload_t *this; - this = (private_id_payload_t*)id_payload_create(payload_type); + this = (private_id_payload_t*)id_payload_create(type); this->id_data = chunk_clone(id->get_encoding(id)); this->id_type = id->get_type(id); this->payload_length += this->id_data.len; return &this->public; } + +/* + * Described in header. + */ +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) +{ + private_id_payload_t *this; + u_int8_t mask; + host_t *net; + + this = (private_id_payload_t*)id_payload_create(ID_V1); + + if (ts->is_host(ts, NULL)) + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR; + } + else + { + this->id_type = ID_IPV6_ADDR; + } + this->id_data = chunk_clone(ts->get_from_address(ts)); + } + else if (ts->to_subnet(ts, &net, &mask)) + { + u_int8_t netmask[16], len, byte; + + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_SUBNET; + len = 4; + } + else + { + this->id_type = ID_IPV6_ADDR_SUBNET; + len = 16; + } + memset(netmask, 0, sizeof(netmask)); + for (byte = 0; byte < sizeof(netmask); byte++) + { + if (mask < 8) + { + netmask[byte] = 0xFF << (8 - mask); + break; + } + netmask[byte] = 0xFF; + mask -= 8; + } + this->id_data = chunk_cat("cc", net->get_address(net), + chunk_create(netmask, len)); + net->destroy(net); + } + else + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_RANGE; + } + else + { + this->id_type = ID_IPV6_ADDR_RANGE; + } + this->id_data = chunk_cat("cc", + ts->get_from_address(ts), ts->get_to_address(ts)); + net->destroy(net); + } + this->port = ts->get_from_port(ts); + this->protocol_id = ts->get_protocol(ts); + this->payload_length += this->id_data.len; + + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 99831f85f..9a6249429 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -28,16 +28,10 @@ typedef struct id_payload_t id_payload_t; #include #include #include +#include /** - * Length of a id payload without the data in bytes. - */ -#define ID_PAYLOAD_HEADER_LENGTH 8 - -/** - * Object representing an IKEv2 ID payload. - * - * The ID payload format is described in RFC section 3.5. + * Object representing an IKEv1 or an IKEv2 ID payload. */ struct id_payload_t { @@ -53,6 +47,20 @@ struct id_payload_t { */ identification_t *(*get_identification) (id_payload_t *this); + /** + * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity. + * + * @return traffic selector, NULL on failure + */ + traffic_selector_t* (*get_ts)(id_payload_t *this); + + /** + * Get encoded payload without fixed payload header (used for IKEv1). + * + * @return encoded payload (gets allocated) + */ + chunk_t (*get_encoded)(id_payload_t *this); + /** * Destroys an id_payload_t object. */ @@ -62,19 +70,27 @@ struct id_payload_t { /** * Creates an empty id_payload_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 + * @return id_payload_t object */ -id_payload_t *id_payload_create(payload_type_t payload_type); +id_payload_t *id_payload_create(payload_type_t type); /** * Creates an id_payload_t from an existing identification_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @param identification identification_t object - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 + * @param id identification_t object + * @return id_payload_t object + */ +id_payload_t *id_payload_create_from_identification(payload_type_t type, + identification_t *id); + +/** + * Create an IKEv1 ID_ADDR_SUBNET/RANGE identity from a traffic selector. + * + * @param ts traffic selector + * @return ID_V1 id_paylad_t object. */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, - identification_t *identification); +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts); #endif /** ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 24d22f3a1..58b624192 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -81,12 +81,27 @@ struct private_ike_header_t { * TRUE, if this is a response, FALSE if its a Request. */ bool response; + + /** + * TRUE, if the packet is encrypted (IKEv1). + */ + bool encryption; + + /** + * TRUE, if the commit flag is set (IKEv1). + */ + bool commit; + + /** + * TRUE, if the auth only flag is set (IKEv1). + */ + bool authonly; } flags; /** * Reserved bits of IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Associated Message-ID. @@ -99,9 +114,15 @@ struct private_ike_header_t { u_int32_t length; }; -ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED, - "EXCHANGE_TYPE_UNDEFINED"); -ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UNDEFINED, +ENUM_BEGIN(exchange_type_names, ID_PROT, TRANSACTION, + "ID_PROT", + "AUTH_ONLY", + "AGGRESSIVE", + "INFORMATIONAL_V1", + "TRANSACTION"); +ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, TRANSACTION, + "QUICK_MODE", + "NEW_GROUP_MODE", "IKE_SA_INIT", "IKE_AUTH", "CREATE_CHILD_SA", @@ -110,18 +131,23 @@ ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UN #ifdef ME ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, IKE_SESSION_RESUME, "ME_CONNECT"); -ENUM_END(exchange_type_names, ME_CONNECT); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, ME_CONNECT, + "EXCHANGE_TYPE_UNDEFINED"); #else -ENUM_END(exchange_type_names, IKE_SESSION_RESUME); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, IKE_SESSION_RESUME, + "EXCHANGE_TYPE_UNDEFINED"); #endif /* ME */ +ENUM_END(exchange_type_names, EXCHANGE_TYPE_UNDEFINED); /** - * Encoding rules to parse or generate a IKEv2-Header. + * Encoding rules to parse or generate a IKE-Header. * * The defined offsets are the positions in a object of type * ike_header_t. */ -encoding_rule_t ike_header_encodings[] = { +static encoding_rule_t encodings[] = { /* 8 Byte SPI, stored in the field initiator_spi */ { IKE_SPI, offsetof(private_ike_header_t, initiator_spi) }, /* 8 Byte SPI, stored in the field responder_spi */ @@ -137,22 +163,20 @@ encoding_rule_t ike_header_encodings[] = { /* 2 Bit reserved bits */ { RESERVED_BIT, offsetof(private_ike_header_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_ike_header_t, reserved[1]) }, - /* 3 Bit flags, stored in the fields response, version and initiator */ + /* 6 flags */ { FLAG, offsetof(private_ike_header_t, flags.response) }, { FLAG, offsetof(private_ike_header_t, flags.version) }, { FLAG, offsetof(private_ike_header_t, flags.initiator) }, - /* 3 Bit reserved bits */ - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[4]) }, + { FLAG, offsetof(private_ike_header_t, flags.authonly) }, + { FLAG, offsetof(private_ike_header_t, flags.commit) }, + { FLAG, offsetof(private_ike_header_t, flags.encryption)}, /* 4 Byte message id, stored in the field message_id */ { U_INT_32, offsetof(private_ike_header_t, message_id) }, /* 4 Byte length fied, stored in the field length */ - { HEADER_LENGTH,offsetof(private_ike_header_t, length) }, + { HEADER_LENGTH, offsetof(private_ike_header_t, length) } }; - -/* 1 2 3 +/* 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! IKE_SA Initiator's SPI ! @@ -172,35 +196,67 @@ encoding_rule_t ike_header_encodings[] = { METHOD(payload_t, verify, status_t, private_ike_header_t *this) { - if ((this->exchange_type < IKE_SA_INIT) || - ((this->exchange_type > INFORMATIONAL) + switch (this->exchange_type) + { + case ID_PROT: + case AGGRESSIVE: + if (this->message_id != 0) + { + return FAILED; + } + /* fall */ + case AUTH_ONLY: + case INFORMATIONAL_V1: + case TRANSACTION: + case QUICK_MODE: + case NEW_GROUP_MODE: + if (this->maj_version != IKEV1_MAJOR_VERSION) + { + return FAILED; + } + break; + case IKE_SA_INIT: + case IKE_AUTH: + case CREATE_CHILD_SA: + case INFORMATIONAL: + case IKE_SESSION_RESUME: #ifdef ME - && (this->exchange_type != ME_CONNECT) + case ME_CONNECT: #endif /* ME */ - )) - { - /* unsupported exchange type */ - return FAILED; + if (this->maj_version != IKEV2_MAJOR_VERSION) + { + return FAILED; + } + break; + default: + /* unsupported exchange type */ + return FAILED; } - if (this->initiator_spi == 0 + if (this->initiator_spi == 0) + { #ifdef ME - /* we allow zero spi for INFORMATIONAL exchanges, - * to allow connectivity checks */ - && this->exchange_type != INFORMATIONAL + if (this->exchange_type != INFORMATIONAL) + /* we allow zero spi for INFORMATIONAL exchanges, + * to allow connectivity checks */ #endif /* ME */ - ) - { - /* initiator spi not set */ - return FAILED; + { + return FAILED; + } } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ike_header_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ike_header_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_ike_header_t *this) { - *rules = ike_header_encodings; - *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t); + return IKE_HEADER_LENGTH; } METHOD(payload_t, get_type, payload_type_t, @@ -311,6 +367,43 @@ METHOD(ike_header_t, set_initiator_flag, void, this->flags.initiator = initiator; } +METHOD(ike_header_t, get_encryption_flag, bool, + private_ike_header_t *this) +{ + return this->flags.encryption; +} + +METHOD(ike_header_t, set_encryption_flag, void, + private_ike_header_t *this, bool encryption) +{ + this->flags.encryption = encryption; +} + + +METHOD(ike_header_t, get_commit_flag, bool, + private_ike_header_t *this) +{ + return this->flags.commit; +} + +METHOD(ike_header_t, set_commit_flag, void, + private_ike_header_t *this, bool commit) +{ + this->flags.commit = commit; +} + +METHOD(ike_header_t, get_authonly_flag, bool, + private_ike_header_t *this) +{ + return this->flags.authonly; +} + +METHOD(ike_header_t, set_authonly_flag, void, + private_ike_header_t *this, bool authonly) +{ + this->flags.authonly = authonly; +} + METHOD(ike_header_t, get_exchange_type, u_int8_t, private_ike_header_t *this) { @@ -353,6 +446,7 @@ ike_header_t *ike_header_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -373,21 +467,38 @@ ike_header_t *ike_header_create() .set_version_flag = _set_version_flag, .get_initiator_flag = _get_initiator_flag, .set_initiator_flag = _set_initiator_flag, + .get_encryption_flag = _get_encryption_flag, + .set_encryption_flag = _set_encryption_flag, + .get_commit_flag = _get_commit_flag, + .set_commit_flag = _set_commit_flag, + .get_authonly_flag = _get_authonly_flag, + .set_authonly_flag = _set_authonly_flag, .get_exchange_type = _get_exchange_type, .set_exchange_type = _set_exchange_type, .get_message_id = _get_message_id, .set_message_id = _set_message_id, .destroy = _destroy, }, - .maj_version = IKE_MAJOR_VERSION, - .min_version = IKE_MINOR_VERSION, - .exchange_type = EXCHANGE_TYPE_UNDEFINED, - .flags = { - .initiator = TRUE, - .version = HIGHER_VERSION_SUPPORTED_FLAG, - }, .length = IKE_HEADER_LENGTH, + .exchange_type = EXCHANGE_TYPE_UNDEFINED, ); return &this->public; } + +/* + * Described in header. + */ +ike_header_t *ike_header_create_version(int major, int minor) +{ + ike_header_t *this = ike_header_create(); + + this->set_maj_version(this, major); + this->set_min_version(this, minor); + if (major == IKEV2_MAJOR_VERSION) + { + this->set_initiator_flag(this, TRUE); + } + return this; +} + diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index 5579a4961..e6b7d0dff 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -30,19 +30,24 @@ typedef struct ike_header_t ike_header_t; #include /** - * Major Version of IKEv2. + * Major Version of IKEv1 we implement. */ -#define IKE_MAJOR_VERSION 2 +#define IKEV1_MAJOR_VERSION 1 /** - * Minor Version of IKEv2. + * Minor Version of IKEv1 we implement. */ -#define IKE_MINOR_VERSION 0 +#define IKEV1_MINOR_VERSION 0 /** - * Flag in IKEv2-Header. Always 0. + * Major Version of IKEv2 we implement. */ -#define HIGHER_VERSION_SUPPORTED_FLAG 0 +#define IKEV2_MAJOR_VERSION 2 + +/** + * Minor Version of IKEv2 we implement. + */ +#define IKEV2_MINOR_VERSION 0 /** * Length of IKE Header in Bytes. @@ -57,9 +62,39 @@ typedef struct ike_header_t ike_header_t; enum exchange_type_t{ /** - * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type. + * Identity Protection (Main mode). */ - EXCHANGE_TYPE_UNDEFINED = 255, + ID_PROT = 2, + + /** + * Authentication Only. + */ + AUTH_ONLY = 3, + + /** + * Aggresive (Aggressive mode) + */ + AGGRESSIVE = 4, + + /** + * Informational in IKEv1 + */ + INFORMATIONAL_V1 = 5, + + /** + * Transaction (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05") + */ + TRANSACTION = 6, + + /** + * Quick Mode + */ + QUICK_MODE = 32, + + /** + * New Group Mode + */ + NEW_GROUP_MODE = 33, /** * IKE_SA_INIT. @@ -77,7 +112,7 @@ enum exchange_type_t{ CREATE_CHILD_SA = 36, /** - * INFORMATIONAL. + * INFORMATIONAL in IKEv2. */ INFORMATIONAL = 37, @@ -85,12 +120,18 @@ enum exchange_type_t{ * IKE_SESSION_RESUME (RFC 5723). */ IKE_SESSION_RESUME = 38, + #ifdef ME /** * ME_CONNECT */ - ME_CONNECT = 240 + ME_CONNECT = 240, #endif /* ME */ + + /** + * Undefined exchange type, in private space. + */ + EXCHANGE_TYPE_UNDEFINED = 255, }; /** @@ -99,12 +140,7 @@ enum exchange_type_t{ extern enum_name_t *exchange_type_names; /** - * An object of this type represents an IKEv2 header and is used to - * generate and parse IKEv2 headers. - * - * The header format of an IKEv2-Message is compatible to the - * ISAKMP-Header format to allow implementations supporting - * both versions of the IKE-protocol. + * An object of this type represents an IKE header of either IKEv1 or IKEv2. */ struct ike_header_t { /** @@ -115,7 +151,7 @@ struct ike_header_t { /** * Get the initiator spi. * - * @return initiator_spi + * @return initiator_spi */ u_int64_t (*get_initiator_spi) (ike_header_t *this); @@ -129,7 +165,7 @@ struct ike_header_t { /** * Get the responder spi. * - * @return responder_spi + * @return responder_spi */ u_int64_t (*get_responder_spi) (ike_header_t *this); @@ -143,7 +179,7 @@ struct ike_header_t { /** * Get the major version. * - * @return major version + * @return major version */ u_int8_t (*get_maj_version) (ike_header_t *this); @@ -157,7 +193,7 @@ struct ike_header_t { /** * Get the minor version. * - * @return minor version + * @return minor version */ u_int8_t (*get_min_version) (ike_header_t *this); @@ -171,7 +207,7 @@ struct ike_header_t { /** * Get the response flag. * - * @return response flag + * @return response flag */ bool (*get_response_flag) (ike_header_t *this); @@ -185,7 +221,7 @@ struct ike_header_t { /** * Get "higher version supported"-flag. * - * @return version flag + * @return version flag */ bool (*get_version_flag) (ike_header_t *this); @@ -199,7 +235,7 @@ struct ike_header_t { /** * Get the initiator flag. * - * @return initiator flag + * @return initiator flag */ bool (*get_initiator_flag) (ike_header_t *this); @@ -210,10 +246,52 @@ struct ike_header_t { */ void (*set_initiator_flag) (ike_header_t *this, bool initiator); + /** + * Get the encryption flag. + * + * @return encryption flag + */ + bool (*get_encryption_flag) (ike_header_t *this); + + /** + * Set the encryption flag. + * + * @param encryption encryption flag + */ + void (*set_encryption_flag) (ike_header_t *this, bool encryption); + + /** + * Get the commit flag. + * + * @return commit flag + */ + bool (*get_commit_flag) (ike_header_t *this); + + /** + * Set the commit flag. + * + * @param commit commit flag + */ + void (*set_commit_flag) (ike_header_t *this, bool commit); + + /** + * Get the authentication only flag. + * + * @return authonly flag + */ + bool (*get_authonly_flag) (ike_header_t *this); + + /** + * Set the authentication only flag. + * + * @param authonly authonly flag + */ + void (*set_authonly_flag) (ike_header_t *this, bool authonly); + /** * Get the exchange type. * - * @return exchange type + * @return exchange type */ u_int8_t (*get_exchange_type) (ike_header_t *this); @@ -227,7 +305,7 @@ struct ike_header_t { /** * Get the message id. * - * @return message id + * @return message id */ u_int32_t (*get_message_id) (ike_header_t *this); @@ -245,10 +323,17 @@ struct ike_header_t { }; /** - * Create an ike_header_t object + * Create an empty ike_header_t object. * * @return ike_header_t object */ ike_header_t *ike_header_create(void); +/** + * Create an ike_header_t object for a specific major/minor version + * + * @return ike_header_t object + */ +ike_header_t *ike_header_create_version(int major, int minor); + #endif /** IKE_HEADER_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 999d73192..438ea46b9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -67,15 +67,17 @@ struct private_ke_payload_t { * Key Exchange Data of this KE payload. */ chunk_t key_exchange_data; + + /** + * Payload type, KEY_EXCHANGE or KEY_EXCHANGE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-KE Payload. - * - * The defined offsets are the positions in a object of type - * private_ke_payload_t. + * Encoding rules for IKEv2 key exchange payload. */ -encoding_rule_t ke_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, /* the critical bit */ @@ -96,7 +98,7 @@ encoding_rule_t ke_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[1])}, /* Key Exchange Data is from variable size */ - { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)} + { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, }; /* @@ -113,23 +115,62 @@ encoding_rule_t ke_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, + /* Reserved Byte */ + { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) }, + /* Key Exchange Data is from variable size */ + { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Key Exchange Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_ke_payload_t *this) { return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ke_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == KEY_EXCHANGE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_ke_payload_t *this) { - *rules = ke_payload_encodings; - *rule_count = countof(ke_payload_encodings); + if (this->type == KEY_EXCHANGE) + { + return 8; + } + return 4; } METHOD(payload_t, get_type, payload_type_t, private_ke_payload_t *this) { - return KEY_EXCHANGE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -172,7 +213,7 @@ METHOD2(payload_t, ke_payload_t, destroy, void, /* * Described in header */ -ke_payload_t *ke_payload_create() +ke_payload_t *ke_payload_create(payload_type_t type) { private_ke_payload_t *this; @@ -181,6 +222,7 @@ ke_payload_t *ke_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -192,22 +234,24 @@ ke_payload_t *ke_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = KE_PAYLOAD_HEADER_LENGTH, .dh_group_number = MODP_NONE, + .type = type, ); + this->payload_length = get_header_length(this); return &this->public; } /* * Described in header */ -ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh) +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh) { - private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(); + private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(type); dh->get_my_public_value(dh, &this->key_exchange_data); this->dh_group_number = dh->get_dh_group(dh); - this->payload_length = this->key_exchange_data.len + KE_PAYLOAD_HEADER_LENGTH; + this->payload_length += this->key_exchange_data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h index 65cc11883..5942954d9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.h +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -31,16 +31,10 @@ typedef struct ke_payload_t ke_payload_t; #include /** - * KE payload length in bytes without any key exchange data. - */ -#define KE_PAYLOAD_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2-KE Payload. - * - * The KE Payload format is described in RFC section 3.4. + * Class representing an IKEv1 or IKEv2 key exchange payload. */ struct ke_payload_t { + /** * The payload_t interface. */ @@ -54,32 +48,34 @@ struct ke_payload_t { chunk_t (*get_key_exchange_data) (ke_payload_t *this); /** - * Gets the Diffie-Hellman Group Number of this KE payload. + * Gets the Diffie-Hellman Group Number of this KE payload (IKEv2 only). * * @return DH Group Number of this payload */ diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); /** - * Destroys an ke_payload_t object. + * Destroys a ke_payload_t object. */ void (*destroy) (ke_payload_t *this); }; /** - * Creates an empty ke_payload_t object + * Creates an empty ke_payload_t object. * - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create(void); +ke_payload_t *ke_payload_create(payload_type_t type); /** - * Creates a ke_payload_t from a diffie_hellman_t + * Creates a ke_payload_t from a diffie_hellman_t. * - * @param diffie_hellman diffie hellman object containing group and key - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @param dh diffie hellman object containing group and key + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create_from_diffie_hellman( - diffie_hellman_t *diffie_hellman); +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh); #endif /** KE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 78000b8c6..3c5eeb535 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -19,6 +19,7 @@ #include "nonce_payload.h" +#include #include typedef struct private_nonce_payload_t private_nonce_payload_t; @@ -57,6 +58,11 @@ struct private_nonce_payload_t { * The contained nonce value. */ chunk_t nonce; + + /** + * Payload type, NONCE or NONCE_V1 + */ + payload_type_t type; }; /** @@ -65,7 +71,7 @@ struct private_nonce_payload_t { * The defined offsets are the positions in a object of type * private_nonce_payload_t. */ -encoding_rule_t nonce_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_nonce_payload_t, next_payload) }, /* the critical bit */ @@ -81,7 +87,7 @@ encoding_rule_t nonce_payload_encodings[] = { /* Length of the whole nonce payload*/ { PAYLOAD_LENGTH, offsetof(private_nonce_payload_t, payload_length) }, /* some nonce bytes, lenth is defined in PAYLOAD_LENGTH */ - { NONCE_DATA, offsetof(private_nonce_payload_t, nonce) }, + { CHUNK_DATA, offsetof(private_nonce_payload_t, nonce) }, }; /* 1 2 3 @@ -98,24 +104,48 @@ encoding_rule_t nonce_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_nonce_payload_t *this) { - if (this->nonce.len < 16 || this->nonce.len > 256) + bool bad_length = FALSE; + + if (this->nonce.len > 256) + { + bad_length = TRUE; + } + if (this->type == NONCE && + this->nonce.len < 16) + { + bad_length = TRUE; + } + if (this->type == NONCE_V1 && + this->nonce.len < 8) + { + bad_length = TRUE; + } + if (bad_length) { + DBG1(DBG_ENC, "%N payload has invalid length (%d bytes)", + payload_type_names, this->type, this->nonce.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_nonce_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_nonce_payload_t *this) { - *rules = nonce_payload_encodings; - *rule_count = countof(nonce_payload_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_nonce_payload_t *this) { - return NONCE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -140,7 +170,7 @@ METHOD(nonce_payload_t, set_nonce, void, private_nonce_payload_t *this, chunk_t nonce) { this->nonce = chunk_clone(nonce); - this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len; + this->payload_length = get_header_length(this) + nonce.len; } METHOD(nonce_payload_t, get_nonce, chunk_t, @@ -159,7 +189,7 @@ METHOD2(payload_t, nonce_payload_t, destroy, void, /* * Described in header */ -nonce_payload_t *nonce_payload_create() +nonce_payload_t *nonce_payload_create(payload_type_t type) { private_nonce_payload_t *this; @@ -168,6 +198,7 @@ nonce_payload_t *nonce_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -179,7 +210,8 @@ nonce_payload_t *nonce_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = NONCE_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h index e9212202e..5c47f5f9f 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.h +++ b/src/libcharon/encoding/payloads/nonce_payload.h @@ -33,14 +33,7 @@ typedef struct nonce_payload_t nonce_payload_t; #define NONCE_SIZE 32 /** - * Length of a nonce payload without a nonce in bytes. - */ -#define NONCE_PAYLOAD_HEADER_LENGTH 4 - -/** - * Object representing an IKEv2 Nonce payload. - * - * The Nonce payload format is described in RFC section 3.3. + * Object representing an IKEv1/IKEv2 Nonce payload. */ struct nonce_payload_t { /** @@ -71,8 +64,9 @@ struct nonce_payload_t { /** * Creates an empty nonce_payload_t object * - * @return nonce_payload_t object + * @param type NONCE or NONCE_V1 + * @return nonce_payload_t object */ -nonce_payload_t *nonce_payload_create(void); +nonce_payload_t *nonce_payload_create(payload_type_t type); #endif /** NONCE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index e03d1af67..d168e1c12 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -36,11 +36,18 @@ ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYN "INVALID_MESSAGE_ID"); ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVALID_SPI"); -ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTRIBUTES_NOT_SUPPORTED", "NO_PROPOSAL_CHOSEN"); -ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, - "INVALID_KE_PAYLOAD"); -ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, +ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, + "PAYLOAD_MALFORMED", + "INVALID_KE_PAYLOAD", + "INVALID_ID_INFORMATION", + "INVALID_CERT_ENCODING", + "INVALID_CERTIFICATE", + "CERT_TYPE_UNSUPPORTED", + "INVALID_CERT_AUTHORITY", + "INVALID_HASH_INFORMATION", "AUTHENTICATION_FAILED"); ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", @@ -102,7 +109,14 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATUS, "SECURE PASSWORD_METHOD", "PSK_PERSIST", "PSK_CONFIRM"); -ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM, +ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD_R_U_THERE", + "DPD_R_U_THERE_ACK"); +ENUM_NEXT(notify_type_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK, + "UNITY_LOAD_BALANCE"); +ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MEDIATION", @@ -127,11 +141,18 @@ ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVAL "INVAL_MID"); ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVAL_SPI"); -ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_short_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTR_UNSUP", "NO_PROP"); -ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, - "INVAL_KE"); -ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, +ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, + "PLD_MAL", + "INVAL_KE", + "INVAL_ID", + "INVAL_CERTEN", + "INVAL_CERT", + "CERT_UNSUP", + "INVAL_CA", + "INVAL_HASH", "AUTH_FAILED"); ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR", @@ -193,7 +214,14 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATU "SEC_PASSWD", "PSK_PST", "PSK_CFM"); -ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM, +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD", + "DPD_ACK"); +ENUM_NEXT(notify_type_short_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK, + "UNITY_LB"); +ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MED", @@ -232,13 +260,18 @@ struct private_notify_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. */ u_int16_t payload_length; + /** + * Domain of interpretation, IKEv1 only. + */ + u_int32_t doi; + /** * Protocol id. */ @@ -262,40 +295,42 @@ struct private_notify_payload_t { /** * Notification data. */ - chunk_t notification_data; + chunk_t notify_data; + + /** + * Type of payload, NOTIFY or NOTIFY_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-Notify Payload. - * - * The defined offsets are the positions in a object of type - * private_notify_payload_t. + * Encoding rules for an IKEv2 notification payload */ -encoding_rule_t notify_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_notify_payload_t, critical) }, + { FLAG, offsetof(private_notify_payload_t, critical) }, /* 7 Bit reserved bits, nowhere stored */ - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, /* Protocol ID as 8 bit field*/ - { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, + { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, /* SPI Size as 8 bit field*/ - { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, /* Notify message type as 16 bit field*/ - { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, /* SPI as variable length field*/ - { SPI, offsetof(private_notify_payload_t, spi) }, + { SPI, offsetof(private_notify_payload_t, spi) }, /* Key Exchange Data is from variable size */ - { NOTIFICATION_DATA,offsetof(private_notify_payload_t, notification_data) } + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) }, }; /* @@ -315,6 +350,57 @@ encoding_rule_t notify_payload_encodings[] = { ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 notification payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + /* DOI as 32 bit field*/ + { U_INT_32, offsetof(private_notify_payload_t, doi) }, + /* Protocol ID as 8 bit field*/ + { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, + /* SPI Size as 8 bit field*/ + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, + /* Notify message type as 16 bit field*/ + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + /* SPI as variable length field*/ + { SPI, offsetof(private_notify_payload_t, spi) }, + /* Key Exchange Data is from variable size */ + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! Notify Message Type ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Notification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_notify_payload_t *this) @@ -337,7 +423,7 @@ METHOD(payload_t, verify, status_t, { case INVALID_KE_PAYLOAD: { - if (this->notification_data.len != 2) + if (this->type == NOTIFY && this->notify_data.len != 2) { bad_length = TRUE; } @@ -347,7 +433,7 @@ METHOD(payload_t, verify, status_t, case NAT_DETECTION_DESTINATION_IP: case ME_CONNECTAUTH: { - if (this->notification_data.len != HASH_SIZE_SHA1) + if (this->notify_data.len != HASH_SIZE_SHA1) { bad_length = TRUE; } @@ -357,7 +443,7 @@ METHOD(payload_t, verify, status_t, case INVALID_MAJOR_VERSION: case NO_PROPOSAL_CHOSEN: { - if (this->notification_data.len != 0) + if (this->type == NOTIFY && this->notify_data.len != 0) { bad_length = TRUE; } @@ -365,7 +451,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP4_ADDRESS: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -373,7 +459,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP6_ADDRESS: { - if (this->notification_data.len != 16) + if (this->notify_data.len != 16) { bad_length = TRUE; } @@ -381,7 +467,7 @@ METHOD(payload_t, verify, status_t, } case AUTH_LIFETIME: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -389,30 +475,37 @@ METHOD(payload_t, verify, status_t, } case IPCOMP_SUPPORTED: { - if (this->notification_data.len != 3) + if (this->notify_data.len != 3) { bad_length = TRUE; } break; } case ME_ENDPOINT: - if (this->notification_data.len != 8 && - this->notification_data.len != 12 && - this->notification_data.len != 24) + if (this->notify_data.len != 8 && + this->notify_data.len != 12 && + this->notify_data.len != 24) { bad_length = TRUE; } break; case ME_CONNECTID: - if (this->notification_data.len < 4 || - this->notification_data.len > 16) + if (this->notify_data.len < 4 || + this->notify_data.len > 16) { bad_length = TRUE; } break; case ME_CONNECTKEY: - if (this->notification_data.len < 16 || - this->notification_data.len > 32) + if (this->notify_data.len < 16 || + this->notify_data.len > 32) + { + bad_length = TRUE; + } + break; + case DPD_R_U_THERE: + case DPD_R_U_THERE_ACK: + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -425,23 +518,38 @@ METHOD(payload_t, verify, status_t, { DBG1(DBG_ENC, "invalid notify data length for %N (%d)", notify_type_names, this->notify_type, - this->notification_data.len); + this->notify_data.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_notify_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == NOTIFY) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_notify_payload_t *this) { - *rules = notify_payload_encodings; - *rule_count = countof(notify_payload_encodings); + if (this->type == NOTIFY) + { + return 8 + this->spi_size; + } + return 12 + this->spi_size; } METHOD(payload_t, get_type, payload_type_t, private_notify_payload_t *this) { - return NOTIFY; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -459,19 +567,9 @@ METHOD(payload_t, set_next_type, void, /** * recompute the payloads length. */ -static void compute_length (private_notify_payload_t *this) +static void compute_length(private_notify_payload_t *this) { - size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH; - - if (this->notification_data.ptr != NULL) - { - length += this->notification_data.len; - } - if (this->spi.ptr != NULL) - { - length += this->spi.len; - } - this->payload_length = length; + this->payload_length = get_header_length(this) + this->notify_data.len; } METHOD(payload_t, get_length, size_t, @@ -539,24 +637,55 @@ METHOD(notify_payload_t, set_spi, void, compute_length(this); } +METHOD(notify_payload_t, get_spi_data, chunk_t, + private_notify_payload_t *this) +{ + switch (this->protocol_id) + { + case PROTO_IKE: + if (this->spi.len == 16) + { + return this->spi; + } + default: + break; + } + return chunk_empty; +} + +METHOD(notify_payload_t, set_spi_data, void, + private_notify_payload_t *this, chunk_t spi) +{ + chunk_free(&this->spi); + switch (this->protocol_id) + { + case PROTO_IKE: + this->spi = chunk_clone(spi); + default: + break; + } + this->spi_size = this->spi.len; + compute_length(this); +} + METHOD(notify_payload_t, get_notification_data, chunk_t, private_notify_payload_t *this) { - return this->notification_data; + return this->notify_data; } METHOD(notify_payload_t, set_notification_data, void, private_notify_payload_t *this, chunk_t data) { - free(this->notification_data.ptr); - this->notification_data = chunk_clone(data); + free(this->notify_data.ptr); + this->notify_data = chunk_clone(data); compute_length(this); } METHOD2(payload_t, notify_payload_t, destroy, void, private_notify_payload_t *this) { - free(this->notification_data.ptr); + free(this->notify_data.ptr); free(this->spi.ptr); free(this); } @@ -564,7 +693,7 @@ METHOD2(payload_t, notify_payload_t, destroy, void, /* * Described in header */ -notify_payload_t *notify_payload_create() +notify_payload_t *notify_payload_create(payload_type_t type) { private_notify_payload_t *this; @@ -573,6 +702,7 @@ notify_payload_t *notify_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -585,13 +715,17 @@ notify_payload_t *notify_payload_create() .set_notify_type = _set_notify_type, .get_spi = _get_spi, .set_spi = _set_spi, + .get_spi_data = _get_spi_data, + .set_spi_data = _set_spi_data, .get_notification_data = _get_notification_data, .set_notification_data = _set_notification_data, .destroy = _destroy, }, + .doi = IKEV1_DOI_IPSEC, .next_payload = NO_PAYLOAD, - .payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH, + .type = type, ); + compute_length(this); return &this->public; } @@ -599,12 +733,12 @@ notify_payload_t *notify_payload_create() * Described in header. */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t notify_type) + payload_type_t type, protocol_id_t protocol, notify_type_t notify) { - notify_payload_t *notify = notify_payload_create(); + notify_payload_t *this = notify_payload_create(type); - notify->set_notify_type(notify, notify_type); - notify->set_protocol_id(notify, protocol_id); + this->set_notify_type(this, notify); + this->set_protocol_id(this, protocol); - return notify; + return this; } diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index ced282700..beec1e233 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -33,25 +33,36 @@ typedef struct notify_payload_t notify_payload_t; #include /** - * Notify payload length in bytes without any spi and notification data. - */ -#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 - -/** - * Notify message types. - * - * See IKEv2 RFC 3.10.1. + * Notify message types for IKEv2, and a subset for IKEv1. */ enum notify_type_t { /* notify error messages */ UNSUPPORTED_CRITICAL_PAYLOAD = 1, + /* IKEv1 alias */ + INVALID_PAYLOAD_TYPE = 1, INVALID_IKE_SPI = 4, INVALID_MAJOR_VERSION = 5, INVALID_SYNTAX = 7, + /* IKEv1 alias */ + INVALID_EXCHANGE_TYPE = 7, INVALID_MESSAGE_ID = 9, INVALID_SPI = 11, + /* IKEv1 only */ + ATTRIBUTES_NOT_SUPPORTED = 13, + /* IKEv1 alias */ NO_PROPOSAL_CHOSEN = 14, + /* IKEv1 only */ + PAYLOAD_MALFORMED = 16, INVALID_KE_PAYLOAD = 17, + /* IKEv1 alias */ + INVALID_KEY_INFORMATION = 17, + /* IKEv1 only */ + INVALID_ID_INFORMATION = 18, + INVALID_CERT_ENCODING = 19, + INVALID_CERTIFICATE = 20, + CERT_TYPE_UNSUPPORTED = 21, + INVALID_CERT_AUTHORITY = 22, + INVALID_HASH_INFORMATION = 23, AUTHENTICATION_FAILED = 24, SINGLE_PAIR_REQUIRED = 34, NO_ADDITIONAL_SAS = 35, @@ -132,6 +143,13 @@ enum notify_type_t { /* PACE - draft-kuegler-ipsecme-pace-ikev2 */ PSK_PERSIST = 16425, PSK_CONFIRM = 16426, + /* IKEv1 initial contact */ + INITIAL_CONTACT_IKEV1 = 24578, + /* IKEv1 DPD */ + DPD_R_U_THERE = 36136, + DPD_R_U_THERE_ACK = 36137, + /* IKEv1 Cisco High Availability */ + UNITY_LOAD_BALANCE = 40501, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, /* IKE-ME, private use */ @@ -213,6 +231,24 @@ struct notify_payload_t { */ void (*set_spi) (notify_payload_t *this, u_int32_t spi); + /** + * Returns the currently set spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @return SPI value + */ + chunk_t (*get_spi_data) (notify_payload_t *this); + + /** + * Sets the spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @param spi SPI value + */ + void (*set_spi_data) (notify_payload_t *this, chunk_t spi); + /** * Returns the currently set notification data of payload. * @@ -241,18 +277,20 @@ struct notify_payload_t { /** * Creates an empty notify_payload_t object * + * @param type payload type, NOTIFY or NOTIFY_V1 * @return created notify_payload_t object */ -notify_payload_t *notify_payload_create(void); +notify_payload_t *notify_payload_create(payload_type_t type); /** * Creates an notify_payload_t object of specific type for specific protocol id. * - * @param protocol_id protocol id (IKE, AH or ESP) - * @param type notify type (see notify_type_t) + * @param type payload type, NOTIFY or NOTIFY_V1 + * @param protocol protocol id (IKE, AH or ESP) + * @param notify type of notify * @return notify_payload_t object */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t type); + payload_type_t type, protocol_id_t protocol, notify_type_t notify); #endif /** NOTIFY_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index a2c0a4385..dc158476b 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -20,6 +20,7 @@ #include #include + #include #include #include @@ -34,13 +35,30 @@ #include #include #include +#include #include - ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, "NO_PAYLOAD"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, - GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD, +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, + "SECURITY_ASSOCIATION_V1", + "PROPOSAL_V1", + "TRANSFORM_V1", + "KEY_EXCHANGE_V1", + "ID_V1", + "CERTIFICATE_V1", + "CERTIFICATE_REQUEST_V1", + "HASH_V1", + "SIGNATURE_V1", + "NONCE_V1", + "NOTIFY_V1", + "DELETE_V1", + "VENDOR_ID_V1", + "CONFIGURATION_V1"); +ENUM_NEXT(payload_type_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT_D_V1", + "NAT_OA_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -61,30 +79,56 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "ID_PEER"); -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #else -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, - GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #endif /* ME */ -ENUM_END(payload_type_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_names, ENCRYPTED_V1); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, "--"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, - GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD, +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, + "SA", + "PROP", + "TRANS", + "KE", + "ID", + "CERT", + "CERTREQ", + "HASH", + "SIG", + "No", + "N", + "D", + "V", + "CP"); +ENUM_NEXT(payload_type_short_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT-D", + "NAT-OA"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1, "SA", "KE", "IDi", @@ -106,24 +150,33 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "IDp"); -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR", + "CATTR", + "E"); #else -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, - GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR", + "CATTR", + "E"); #endif /* ME */ -ENUM_END(payload_type_short_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_short_names, ENCRYPTED_V1); /* * see header @@ -135,29 +188,36 @@ payload_t *payload_create(payload_type_t type) case HEADER: return (payload_t*)ike_header_create(); case SECURITY_ASSOCIATION: - return (payload_t*)sa_payload_create(); + case SECURITY_ASSOCIATION_V1: + return (payload_t*)sa_payload_create(type); case PROPOSAL_SUBSTRUCTURE: - return (payload_t*)proposal_substructure_create(); + case PROPOSAL_SUBSTRUCTURE_V1: + return (payload_t*)proposal_substructure_create(type); case TRANSFORM_SUBSTRUCTURE: - return (payload_t*)transform_substructure_create(); + case TRANSFORM_SUBSTRUCTURE_V1: + return (payload_t*)transform_substructure_create(type); case TRANSFORM_ATTRIBUTE: - return (payload_t*)transform_attribute_create(); + case TRANSFORM_ATTRIBUTE_V1: + return (payload_t*)transform_attribute_create(type); case NONCE: - return (payload_t*)nonce_payload_create(); + case NONCE_V1: + return (payload_t*)nonce_payload_create(type); case ID_INITIATOR: - return (payload_t*)id_payload_create(ID_INITIATOR); case ID_RESPONDER: - return (payload_t*)id_payload_create(ID_RESPONDER); + case ID_V1: + case NAT_OA_V1: #ifdef ME case ID_PEER: - return (payload_t*)id_payload_create(ID_PEER); #endif /* ME */ + return (payload_t*)id_payload_create(type); case AUTHENTICATION: return (payload_t*)auth_payload_create(); case CERTIFICATE: - return (payload_t*)cert_payload_create(); + case CERTIFICATE_V1: + return (payload_t*)cert_payload_create(type); case CERTIFICATE_REQUEST: - return (payload_t*)certreq_payload_create(); + case CERTIFICATE_REQUEST_V1: + return (payload_t*)certreq_payload_create(type); case TRAFFIC_SELECTOR_SUBSTRUCTURE: return (payload_t*)traffic_selector_substructure_create(); case TRAFFIC_SELECTOR_INITIATOR: @@ -165,21 +225,32 @@ payload_t *payload_create(payload_type_t type) case TRAFFIC_SELECTOR_RESPONDER: return (payload_t*)ts_payload_create(FALSE); case KEY_EXCHANGE: - return (payload_t*)ke_payload_create(); + case KEY_EXCHANGE_V1: + return (payload_t*)ke_payload_create(type); case NOTIFY: - return (payload_t*)notify_payload_create(); + case NOTIFY_V1: + return (payload_t*)notify_payload_create(type); case DELETE: - return (payload_t*)delete_payload_create(0); + case DELETE_V1: + return (payload_t*)delete_payload_create(type, 0); case VENDOR_ID: - return (payload_t*)vendor_id_payload_create(); + case VENDOR_ID_V1: + return (payload_t*)vendor_id_payload_create(type); + case HASH_V1: + case SIGNATURE_V1: + case NAT_D_V1: + return (payload_t*)hash_payload_create(type); case CONFIGURATION: - return (payload_t*)cp_payload_create(); + case CONFIGURATION_V1: + return (payload_t*)cp_payload_create(type); case CONFIGURATION_ATTRIBUTE: - return (payload_t*)configuration_attribute_create(); + case CONFIGURATION_ATTRIBUTE_V1: + return (payload_t*)configuration_attribute_create(type); case EXTENSIBLE_AUTHENTICATION: return (payload_t*)eap_payload_create(); case ENCRYPTED: - return (payload_t*)encryption_payload_create(); + case ENCRYPTED_V1: + return (payload_t*)encryption_payload_create(type); default: return (payload_t*)unknown_payload_create(type); } @@ -190,8 +261,19 @@ payload_t *payload_create(payload_type_t type) */ bool payload_is_known(payload_type_t type) { - if (type == HEADER || - (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION)) + if (type == HEADER) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION_V1 && type <= CONFIGURATION_V1) + { + return TRUE; + } + if (type >= NAT_D_V1 && type <= NAT_OA_V1) { return TRUE; } @@ -210,10 +292,9 @@ bool payload_is_known(payload_type_t type) void* payload_get_field(payload_t *payload, encoding_type_t type, u_int skip) { encoding_rule_t *rule; - size_t count; - int i; + int i, count; - payload->get_encoding_rules(payload, &rule, &count); + count = payload->get_encoding_rules(payload, &rule); for (i = 0; i < count; i++) { if (rule[i].type == type && skip-- == 0) diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index a9af29b5b..d5e862601 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -29,20 +29,104 @@ typedef struct payload_t payload_t; #include #include +/** + * Domain of interpretation used by IPsec/IKEv1 + */ +#define IKEV1_DOI_IPSEC 1 /** - * Payload-Types of a IKEv2-Message. + * Payload-Types of an IKE message. * * Header and substructures are also defined as * payload types with values from PRIVATE USE space. */ -enum payload_type_t{ +enum payload_type_t { /** * End of payload list in next_payload */ NO_PAYLOAD = 0, + /** + * The security association (SA) payload containing proposals. + */ + SECURITY_ASSOCIATION_V1 = 1, + + /** + * The proposal payload, containing transforms. + */ + PROPOSAL_V1 = 2, + + /** + * The transform payload. + */ + TRANSFORM_V1 = 3, + + /** + * The key exchange (KE) payload containing diffie-hellman values. + */ + KEY_EXCHANGE_V1 = 4, + + /** + * ID payload. + */ + ID_V1 = 5, + + /** + * Certificate payload with certificates (CERT). + */ + CERTIFICATE_V1 = 6, + + /** + * Certificate request payload. + */ + CERTIFICATE_REQUEST_V1 = 7, + + /** + * Hash payload. + */ + HASH_V1 = 8, + + /** + * Signature payload + */ + SIGNATURE_V1 = 9, + + /** + * Nonce payload. + */ + NONCE_V1 = 10, + + /** + * Notification payload. + */ + NOTIFY_V1 = 11, + + /** + * Delete payload. + */ + DELETE_V1 = 12, + + /** + * Vendor id payload. + */ + VENDOR_ID_V1 = 13, + + /** + * Attribute payload (ISAKMP Mode Config, aka configuration payload. + */ + CONFIGURATION_V1 = 14, + + /** + * NAT discovery payload (NAT-D). + */ + NAT_D_V1 = 20, + + /** + * NAT original address payload (NAT-OA) + */ + NAT_OA_V1 = 21, + /** * The security association (SA) payload containing proposals. */ @@ -139,50 +223,60 @@ enum payload_type_t{ /** * Header has a value of PRIVATE USE space. * - * This payload type is not sent over wire and just - * used internally to handle IKEv2-Header like a payload. + * This type and all the following are never sent over wire and are + * used internally only. */ HEADER = 256, /** - * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a proposal substructure like a payload. + * PROPOSAL_SUBSTRUCTURE, IKEv2 proposals in a SA payload. */ - PROPOSAL_SUBSTRUCTURE = 257, + PROPOSAL_SUBSTRUCTURE, /** - * TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform substructure like a payload. + * PROPOSAL_SUBSTRUCTURE_V1, IKEv1 proposals in a SA payload. */ - TRANSFORM_SUBSTRUCTURE = 258, + PROPOSAL_SUBSTRUCTURE_V1, /** - * TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_SUBSTRUCTURE, IKEv2 transforms in a proposal substructure. */ - TRANSFORM_ATTRIBUTE = 259, + TRANSFORM_SUBSTRUCTURE, /** - * TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform selector like a payload. + * TRANSFORM_SUBSTRUCTURE_V1, IKEv1 transforms in a proposal substructure. */ - TRAFFIC_SELECTOR_SUBSTRUCTURE = 260, + TRANSFORM_SUBSTRUCTURE_V1, /** - * CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_ATTRIBUTE, IKEv2 attribute in a transform. */ - CONFIGURATION_ATTRIBUTE = 261, + TRANSFORM_ATTRIBUTE, + + /** + * TRANSFORM_ATTRIBUTE_V1, IKEv1 attribute in a transform. + */ + TRANSFORM_ATTRIBUTE_V1, + + /** + * TRAFFIC_SELECTOR_SUBSTRUCTURE, traffic selector in a TS payload. + */ + TRAFFIC_SELECTOR_SUBSTRUCTURE, + + /** + * CONFIGURATION_ATTRIBUTE, IKEv2 attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE, + + /** + * CONFIGURATION_ATTRIBUTE_V1, IKEv1 attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE_V1, + + /** + * This is not really a payload, but rather the complete IKEv1 message. + */ + ENCRYPTED_V1, }; /** @@ -207,43 +301,50 @@ struct payload_t { /** * Get encoding rules for this payload. * - * @param rules location to store pointer of first rule - * @param rule_count location to store number of rules + * @param rules location to store pointer to rules + * @return number of rules + */ + int (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules); + + /** + * Get non-variable header length for a variable length payload. + * + * @return fixed length of the payload */ - void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); + int (*get_header_length)(payload_t *this); /** * Get type of payload. * - * @return type of this payload + * @return type of this payload */ payload_type_t (*get_type) (payload_t *this); /** * Get type of next payload or NO_PAYLOAD (0) if this is the last one. * - * @return type of next payload + * @return type of next payload */ payload_type_t (*get_next_type) (payload_t *this); /** * Set type of next payload. * - * @param type type of next payload + * @param type type of next payload */ void (*set_next_type) (payload_t *this,payload_type_t type); /** * Get length of payload. * - * @return length of this payload + * @return length of this payload */ size_t (*get_length) (payload_t *this); /** * Verifies payload structure and makes consistence check. * - * @return SUCCESS, FAILED if consistence not given + * @return SUCCESS, FAILED if consistence not given */ status_t (*verify) (payload_t *this); diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 4753d574d..653f51a46 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,7 +26,7 @@ #include /** - * IKEv1 Value for a proposal payload. + * IKEv2 Value for a proposal payload. */ #define PROPOSAL_TYPE_VALUE 2 @@ -84,16 +85,43 @@ struct private_proposal_substructure_t { /** * Transforms are stored in a linked_list_t. */ - linked_list_t * transforms; + linked_list_t *transforms; + + /** + * Type of this payload, PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a Proposal substructure. - * - * The defined offsets are the positions in a object of type - * private_proposal_substructure_t. + * Encoding rules for a IKEv1 Proposal substructure. + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, + /* 1 Reserved Byte */ + { RESERVED_BYTE, offsetof(private_proposal_substructure_t, reserved) }, + /* Length of the whole proposal substructure payload*/ + { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) }, + /* proposal number is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) }, + /* protocol ID is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) }, + /* SPI Size has its own type */ + { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) }, + /* Number of transforms is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, + /* SPI is a chunk of variable size*/ + { SPI, offsetof(private_proposal_substructure_t, spi) }, + /* Transforms are stored in a transform substructure list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1, + offsetof(private_proposal_substructure_t, transforms) }, +}; + +/** + * Encoding rules for a IKEv2 Proposal substructure. */ -encoding_rule_t proposal_substructure_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, /* 1 Reserved Byte */ @@ -110,9 +138,9 @@ encoding_rule_t proposal_substructure_encodings[] = { { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, /* SPI is a chunk of variable size*/ { SPI, offsetof(private_proposal_substructure_t, spi) }, - /* Transforms are stored in a transform substructure, - offset points to a linked_list_t pointer */ - { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) } + /* Transforms are stored in a transform substructure list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE, + offsetof(private_proposal_substructure_t, transforms) }, }; /* @@ -131,6 +159,149 @@ encoding_rule_t proposal_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encryption. + */ +typedef enum { + IKEV1_ENCR_DES_CBC = 1, + IKEV1_ENCR_IDEA_CBC = 2, + IKEV1_ENCR_BLOWFISH_CBC = 3, + IKEV1_ENCR_RC5_R16_B64_CBC = 4, + IKEV1_ENCR_3DES_CBC = 5, + IKEV1_ENCR_CAST_CBC = 6, + IKEV1_ENCR_AES_CBC = 7, + IKEV1_ENCR_CAMELLIA_CBC = 8, + /* FreeS/WAN proprietary */ + IKEV1_ENCR_SERPENT_CBC = 65004, + IKEV1_ENCR_TWOFISH_CBC = 65005, +} ikev1_encryption_t; + +/** + * IKEv1 hash. + */ +typedef enum { + IKEV1_HASH_MD5 = 1, + IKEV1_HASH_SHA1 = 2, + IKEV1_HASH_TIGER = 3, + IKEV1_HASH_SHA2_256 = 4, + IKEV1_HASH_SHA2_384 = 5, + IKEV1_HASH_SHA2_512 = 6, +} ikev1_hash_t; + +/** + * IKEv1 Transform ID IKE. + */ +typedef enum { + IKEV1_TRANSID_KEY_IKE = 1, +} ikev1_ike_transid_t; + +/** + * IKEv1 Transform ID ESP encryption algorithm. + */ +typedef enum { + IKEV1_ESP_ENCR_DES_IV64 = 1, + IKEV1_ESP_ENCR_DES = 2, + IKEV1_ESP_ENCR_3DES = 3, + IKEV1_ESP_ENCR_RC5 = 4, + IKEV1_ESP_ENCR_IDEA = 5, + IKEV1_ESP_ENCR_CAST = 6, + IKEV1_ESP_ENCR_BLOWFISH = 7, + IKEV1_ESP_ENCR_3IDEA = 8, + IKEV1_ESP_ENCR_DES_IV32 = 9, + IKEV1_ESP_ENCR_RC4 = 10, + IKEV1_ESP_ENCR_NULL = 11, + IKEV1_ESP_ENCR_AES_CBC = 12, + IKEV1_ESP_ENCR_AES_CTR = 13, + IKEV1_ESP_ENCR_AES_CCM_8 = 14, + IKEV1_ESP_ENCR_AES_CCM_12 = 15, + IKEV1_ESP_ENCR_AES_CCM_16 = 16, + IKEV1_ESP_ENCR_AES_GCM_8 = 18, + IKEV1_ESP_ENCR_AES_GCM_12 = 19, + IKEV1_ESP_ENCR_AES_GCM_16 = 20, + IKEV1_ESP_ENCR_SEED_CBC = 21, + IKEV1_ESP_ENCR_CAMELLIA = 22, + IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC = 23, + /* FreeS/WAN proprietary */ + IKEV1_ESP_ENCR_SERPENT = 252, + IKEV1_ESP_ENCR_TWOFISH = 253, +} ikev1_esp_encr_transid_t; + +/** + * IKEv1 Transform ID ESP authentication algorithm. + */ +typedef enum { + IKEV1_ESP_AUTH_HMAC_MD5 = 1, + IKEV1_ESP_AUTH_HMAC_SHA = 2, + IKEV1_ESP_AUTH_DES_MAC = 3, + IKEV1_ESP_AUTH_KPDK = 4, + IKEV1_ESP_AUTH_HMAC_SHA2_256 = 5, + IKEV1_ESP_AUTH_HMAC_SHA2_384 = 6, + IKEV1_ESP_AUTH_HMAC_SHA2_512 = 7, + IKEV1_ESP_AUTH_HMAC_RIPEMD = 8, + IKEV1_ESP_AUTH_AES_XCBC_MAC = 9, + IKEV1_ESP_AUTH_SIG_RSA = 10, + IKEV1_ESP_AUTH_AES_128_GMAC = 11, + IKEV1_ESP_AUTH_AES_192_GMAC = 12, + IKEV1_ESP_AUTH_AES_256_GMAC = 13, +} ikev1_esp_auth_transid_it; + +/** + * IKEv1 ESP Encapsulation mode. + */ +typedef enum { + IKEV1_ENCAP_TUNNEL = 1, + IKEV1_ENCAP_TRANSPORT = 2, + IKEV1_ENCAP_UDP_TUNNEL = 3, + IKEV1_ENCAP_UDP_TRANSPORT = 4, +} ikev1_esp_encap_t; + +/** + * IKEv1 Life duration types. + */ +typedef enum { + IKEV1_LIFE_TYPE_SECONDS = 1, + IKEV1_LIFE_TYPE_KILOBYTES = 2, +} ikev1_life_type_t; + +/** + * IKEv1 authentication methods + */ +typedef enum { + IKEV1_AUTH_PSK = 1, + IKEV1_AUTH_DSS_SIG = 2, + IKEV1_AUTH_RSA_SIG = 3, + IKEV1_AUTH_RSA_ENC = 4, + IKEV1_AUTH_RSA_ENC_REV = 5, + IKEV1_AUTH_ECDSA_256 = 9, + IKEV1_AUTH_ECDSA_384 = 10, + IKEV1_AUTH_ECDSA_521 = 11, + /* XAuth Modes */ + IKEV1_AUTH_XAUTH_INIT_PSK = 65001, + IKEV1_AUTH_XAUTH_RESP_PSK = 65002, + IKEV1_AUTH_XAUTH_INIT_DSS = 65003, + IKEV1_AUTH_XAUTH_RESP_DSS = 65004, + IKEV1_AUTH_XAUTH_INIT_RSA = 65005, + IKEV1_AUTH_XAUTH_RESP_RSA = 65006, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC = 65007, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010, + /* Hybrid Modes */ + IKEV1_AUTH_HYBRID_INIT_RSA = 64221, + IKEV1_AUTH_HYBRID_RESP_RSA = 64222, + IKEV1_AUTH_HYBRID_INIT_DSS = 64223, + IKEV1_AUTH_HYBRID_RESP_DSS = 64224, +} ikev1_auth_method_t; + +/** + * IKEv1 IPComp transform IDs + */ +typedef enum { + IKEV1_IPCOMP_OUI = 1, + IKEV1_IPCOMP_DEFLATE = 2, + IKEV1_IPCOMP_LZS = 3, +} ikev1_ipcomp_transform_t; + METHOD(payload_t, verify, status_t, private_proposal_substructure_t *this) { @@ -153,12 +324,19 @@ METHOD(payload_t, verify, status_t, switch (this->protocol_id) { + case PROTO_IPCOMP: + if (this->spi.len != 2) + { + DBG1(DBG_ENC, "invalid CPI length in IPCOMP proposal"); + return FAILED; + } + break; case PROTO_AH: case PROTO_ESP: if (this->spi.len != 4) { DBG1(DBG_ENC, "invalid SPI length in %N proposal", - protocol_id_names, this->protocol_id); + protocol_id_names, this->protocol_id); return FAILED; } break; @@ -188,18 +366,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_proposal_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_proposal_substructure_t *this, encoding_rule_t **rules) { - *rules = proposal_substructure_encodings; - *rule_count = countof(proposal_substructure_encodings); + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_proposal_substructure_t *this) +{ + return 8 + this->spi_size; } METHOD(payload_t, get_type, payload_type_t, private_proposal_substructure_t *this) { - return PROPOSAL_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -222,7 +410,7 @@ static void compute_length(private_proposal_substructure_t *this) payload_t *transform; this->transforms_count = 0; - this->proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->spi.len; + this->proposal_length = get_header_length(this); enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { @@ -301,45 +489,486 @@ METHOD(proposal_substructure_t, get_spi, chunk_t, return this->spi; } -METHOD(proposal_substructure_t, get_proposal, proposal_t*, - private_proposal_substructure_t *this) +METHOD(proposal_substructure_t, get_cpi, bool, + private_proposal_substructure_t *this, u_int16_t *cpi) { - enumerator_t *enumerator; + transform_substructure_t *transform; - proposal_t *proposal; - u_int64_t spi; + enumerator_t *enumerator; - proposal = proposal_create(this->protocol_id, this->proposal_number); + if (this->protocol_id != PROTO_IPCOMP) + { + return FALSE; + } enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { - transform_type_t transform_type; - u_int16_t transform_id; - u_int16_t key_length = 0; + if (transform->get_transform_id(transform) == IKEV1_IPCOMP_DEFLATE) + { + if (cpi) + { + *cpi = *((u_int16_t*)this->spi.ptr); + } + enumerator->destroy(enumerator); + return TRUE; + } + } + enumerator->destroy(enumerator); + return FALSE; +} - transform_type = transform->get_transform_type(transform); - transform_id = transform->get_transform_id(transform); - transform->get_key_length(transform, &key_length); +/** + * Add a transform to a proposal for IKEv2 + */ +static void add_to_proposal_v2(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t key_length = 0; - proposal->add_algorithm(proposal, transform_type, transform_id, key_length); + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + if (tattr->get_attribute_type(tattr) == TATTR_IKEV2_KEY_LENGTH) + { + key_length = tattr->get_value(tattr); + break; + } } enumerator->destroy(enumerator); + proposal->add_algorithm(proposal, + transform->get_transform_type_or_number(transform), + transform->get_transform_id(transform), key_length); +} + +/** + * Map IKEv1 to IKEv2 algorithms + */ +typedef struct { + u_int16_t ikev1; + u_int16_t ikev2; +} algo_map_t; + +/** + * Encryption algorithm mapping + */ +static algo_map_t map_encr[] = { + { IKEV1_ENCR_DES_CBC, ENCR_DES }, + { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, + { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, + { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, + { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, + { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, + { IKEV1_ENCR_SERPENT_CBC, ENCR_SERPENT_CBC }, + { IKEV1_ENCR_TWOFISH_CBC, ENCR_TWOFISH_CBC }, +}; + +/** + * Integrity algorithm mapping + */ +static algo_map_t map_integ[] = { + { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, + { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, +}; + +/** + * PRF algorithm mapping + */ +static algo_map_t map_prf[] = { + { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, + { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, + { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, + { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, + { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, +}; + +/** + * ESP encryption algorithm mapping + */ +static algo_map_t map_esp_encr[] = { + { IKEV1_ESP_ENCR_DES_IV64, ENCR_DES_IV64 }, + { IKEV1_ESP_ENCR_DES, ENCR_DES }, + { IKEV1_ESP_ENCR_3DES, ENCR_3DES }, + { IKEV1_ESP_ENCR_RC5, ENCR_RC5 }, + { IKEV1_ESP_ENCR_IDEA, ENCR_IDEA }, + { IKEV1_ESP_ENCR_CAST, ENCR_CAST }, + { IKEV1_ESP_ENCR_BLOWFISH, ENCR_BLOWFISH }, + { IKEV1_ESP_ENCR_3IDEA, ENCR_3IDEA }, + { IKEV1_ESP_ENCR_DES_IV32, ENCR_DES_IV32 }, + { IKEV1_ESP_ENCR_NULL, ENCR_NULL }, + { IKEV1_ESP_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ESP_ENCR_AES_CTR, ENCR_AES_CTR }, + { IKEV1_ESP_ENCR_AES_CCM_8, ENCR_AES_CCM_ICV8 }, + { IKEV1_ESP_ENCR_AES_CCM_12, ENCR_AES_CCM_ICV12 }, + { IKEV1_ESP_ENCR_AES_CCM_16, ENCR_AES_CCM_ICV16 }, + { IKEV1_ESP_ENCR_AES_GCM_8, ENCR_AES_GCM_ICV8 }, + { IKEV1_ESP_ENCR_AES_GCM_12, ENCR_AES_GCM_ICV12 }, + { IKEV1_ESP_ENCR_AES_GCM_16, ENCR_AES_GCM_ICV16 }, + { IKEV1_ESP_ENCR_CAMELLIA, ENCR_CAMELLIA_CBC }, + { IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC, ENCR_NULL_AUTH_AES_GMAC }, + { IKEV1_ESP_ENCR_SERPENT, ENCR_SERPENT_CBC }, + { IKEV1_ESP_ENCR_TWOFISH, ENCR_TWOFISH_CBC }, +}; + +/** + * ESP authentication algorithm mapping + */ +static algo_map_t map_esp_auth[] = { + { IKEV1_ESP_AUTH_HMAC_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_ESP_AUTH_HMAC_SHA, AUTH_HMAC_SHA1_96 }, + { IKEV1_ESP_AUTH_DES_MAC, AUTH_DES_MAC }, + { IKEV1_ESP_AUTH_KPDK, AUTH_KPDK_MD5 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 }, + { IKEV1_ESP_AUTH_AES_XCBC_MAC, AUTH_AES_XCBC_96 }, + { IKEV1_ESP_AUTH_AES_128_GMAC, AUTH_AES_128_GMAC }, + { IKEV1_ESP_AUTH_AES_192_GMAC, AUTH_AES_192_GMAC }, + { IKEV1_ESP_AUTH_AES_256_GMAC, AUTH_AES_256_GMAC }, +}; + +/** + * Get IKEv2 algorithm from IKEv1 identifier + */ +static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + u_int16_t def; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_encr; + count = countof(map_encr); + def = ENCR_UNDEFINED; + break; + case INTEGRITY_ALGORITHM: + map = map_integ; + count = countof(map_integ); + def = AUTH_UNDEFINED; + break; + case PSEUDO_RANDOM_FUNCTION: + map = map_prf; + count = countof(map_prf); + def = PRF_UNDEFINED; + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev1 == value) + { + return map[i].ikev2; + } + } + return def; +} + +/** + * Get IKEv1 algorithm from IKEv2 identifier + */ +static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_encr; + count = countof(map_encr); + break; + case INTEGRITY_ALGORITHM: + map = map_integ; + count = countof(map_integ); + break; + case PSEUDO_RANDOM_FUNCTION: + map = map_prf; + count = countof(map_prf); + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev2 == value) + { + return map[i].ikev1; + } + } + return 0; +} + +/** + * Get IKEv2 algorithm from IKEv1 ESP transaction ID + */ +static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + u_int16_t def; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_esp_encr; + count = countof(map_esp_encr); + def = ENCR_UNDEFINED; + break; + case INTEGRITY_ALGORITHM: + map = map_esp_auth; + count = countof(map_esp_auth); + def = AUTH_UNDEFINED; + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev1 == value) + { + return map[i].ikev2; + } + } + return def; +} + +/** + * Get IKEv1 ESP transaction ID from IKEv2 identifier + */ +static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_esp_encr; + count = countof(map_esp_encr); + break; + case INTEGRITY_ALGORITHM: + map = map_esp_auth; + count = countof(map_esp_auth); + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev2 == value) + { + return map[i].ikev1; + } + } + return 0; +} +/** + * Get IKEv1 authentication attribute from auth_method_t + */ +static u_int16_t get_ikev1_auth(auth_method_t method) +{ + switch (method) + { + case AUTH_RSA: + return IKEV1_AUTH_RSA_SIG; + case AUTH_DSS: + return IKEV1_AUTH_DSS_SIG; + case AUTH_XAUTH_INIT_PSK: + return IKEV1_AUTH_XAUTH_INIT_PSK; + case AUTH_XAUTH_RESP_PSK: + return IKEV1_AUTH_XAUTH_RESP_PSK; + case AUTH_XAUTH_INIT_RSA: + return IKEV1_AUTH_XAUTH_INIT_RSA; + case AUTH_XAUTH_RESP_RSA: + return IKEV1_AUTH_XAUTH_RESP_RSA; + case AUTH_HYBRID_INIT_RSA: + return IKEV1_AUTH_HYBRID_INIT_RSA; + case AUTH_HYBRID_RESP_RSA: + return IKEV1_AUTH_HYBRID_RESP_RSA; + case AUTH_ECDSA_256: + return IKEV1_AUTH_ECDSA_256; + case AUTH_ECDSA_384: + return IKEV1_AUTH_ECDSA_384; + case AUTH_ECDSA_521: + return IKEV1_AUTH_ECDSA_521; + case AUTH_PSK: + default: + return IKEV1_AUTH_PSK; + } +} + +/** + * Get IKEv1 encapsulation mode + */ +static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp) +{ + switch (mode) + { + case MODE_TUNNEL: + return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL; + case MODE_TRANSPORT: + return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT; + default: + return IKEV1_ENCAP_TUNNEL; + } +} + +/** + * Add an IKE transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_ike(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t value, key_length = 0; + u_int16_t encr = ENCR_UNDEFINED; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH1_ENCRYPTION_ALGORITHM: + encr = get_alg_from_ikev1(ENCRYPTION_ALGORITHM, value); + break; + case TATTR_PH1_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH1_HASH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); + proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, + get_alg_from_ikev1(PSEUDO_RANDOM_FUNCTION, value), 0); + break; + case TATTR_PH1_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (encr != ENCR_UNDEFINED) + { + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, key_length); + } +} + +/** + * Add an ESP transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_esp(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t encr, value, key_length = 0; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH2_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH2_AUTH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1_transid(INTEGRITY_ALGORITHM, + value), 0); + break; + case TATTR_PH2_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: handle ESN attribute */ + proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + NO_EXT_SEQ_NUMBERS, 0); + encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM, + transform->get_transform_id(transform)); + if (encr) + { + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, + key_length); + } +} + +METHOD(proposal_substructure_t, get_proposals, void, + private_proposal_substructure_t *this, linked_list_t *proposals) +{ + transform_substructure_t *transform; + enumerator_t *enumerator; + proposal_t *proposal = NULL; + u_int64_t spi = 0; + switch (this->spi.len) { case 4: - spi = *((u_int32_t*)this->spi.ptr); + spi = *((u_int32_t*)this->spi.ptr); break; case 8: spi = *((u_int64_t*)this->spi.ptr); break; default: - spi = 0; + break; } - proposal->set_spi(proposal, spi); - return proposal; + enumerator = this->transforms->create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &transform)) + { + if (!proposal) + { + proposal = proposal_create(this->protocol_id, this->proposal_number); + proposal->set_spi(proposal, spi); + proposals->insert_last(proposals, proposal); + } + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + add_to_proposal_v2(proposal, transform); + } + else + { + switch (this->protocol_id) + { + case PROTO_IKE: + add_to_proposal_v1_ike(proposal, transform); + break; + case PROTO_ESP: + add_to_proposal_v1_esp(proposal, transform); + break; + default: + break; + } + /* create a new proposal for each transform in IKEv1 */ + proposal = NULL; + } + } + enumerator->destroy(enumerator); } METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, @@ -348,11 +977,170 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, return this->transforms->create_enumerator(this->transforms); } +/** + * Get an attribute from any transform, 0 if not found + */ +static u_int64_t get_attr(private_proposal_substructure_t *this, + transform_attribute_type_t type) +{ + enumerator_t *transforms, *attributes; + transform_substructure_t *transform; + transform_attribute_t *attr; + + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) + { + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == type) + { + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); + } + } + attributes->destroy(attributes); + } + transforms->destroy(transforms); + return 0; +} + +/** + * Look up a lifetime duration of a given kind in all transforms + */ +static u_int64_t get_life_duration(private_proposal_substructure_t *this, + transform_attribute_type_t type_attr, ikev1_life_type_t type, + transform_attribute_type_t dur_attr) +{ + enumerator_t *transforms, *attributes; + transform_substructure_t *transform; + transform_attribute_t *attr; + + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) + { + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == type_attr && + attr->get_value(attr) == type) + { /* got type attribute, look for duration following next */ + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == dur_attr) + { + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); + } + } + } + } + attributes->destroy(attributes); + } + transforms->destroy(transforms); + return 0; +} + +METHOD(proposal_substructure_t, get_lifetime, u_int32_t, + private_proposal_substructure_t *this) +{ + u_int32_t duration; + + switch (this->protocol_id) + { + case PROTO_IKE: + return get_life_duration(this, TATTR_PH1_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION); + case PROTO_ESP: + duration = get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH2_SA_LIFE_DURATION); + if (!duration) + { /* default to 8 hours, RFC 2407 */ + return 28800; + } + return duration; + default: + return 0; + } +} + +METHOD(proposal_substructure_t, get_lifebytes, u_int64_t, + private_proposal_substructure_t *this) +{ + switch (this->protocol_id) + { + case PROTO_ESP: + return 1000 * get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_KILOBYTES, TATTR_PH2_SA_LIFE_DURATION); + case PROTO_IKE: + default: + return 0; + } +} + +METHOD(proposal_substructure_t, get_auth_method, auth_method_t, + private_proposal_substructure_t *this) +{ + switch (get_attr(this, TATTR_PH1_AUTH_METHOD)) + { + case IKEV1_AUTH_PSK: + return AUTH_PSK; + case IKEV1_AUTH_RSA_SIG: + return AUTH_RSA; + case IKEV1_AUTH_DSS_SIG: + return AUTH_DSS; + case IKEV1_AUTH_XAUTH_INIT_PSK: + return AUTH_XAUTH_INIT_PSK; + case IKEV1_AUTH_XAUTH_RESP_PSK: + return AUTH_XAUTH_RESP_PSK; + case IKEV1_AUTH_XAUTH_INIT_RSA: + return AUTH_XAUTH_INIT_RSA; + case IKEV1_AUTH_XAUTH_RESP_RSA: + return AUTH_XAUTH_RESP_RSA; + case IKEV1_AUTH_HYBRID_INIT_RSA: + return AUTH_HYBRID_INIT_RSA; + case IKEV1_AUTH_HYBRID_RESP_RSA: + return AUTH_HYBRID_RESP_RSA; + case IKEV1_AUTH_ECDSA_256: + return AUTH_ECDSA_256; + case IKEV1_AUTH_ECDSA_384: + return AUTH_ECDSA_384; + case IKEV1_AUTH_ECDSA_521: + return AUTH_ECDSA_521; + default: + return AUTH_NONE; + } +} + +METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t, + private_proposal_substructure_t *this, bool *udp) +{ + *udp = FALSE; + switch (get_attr(this, TATTR_PH2_ENCAP_MODE)) + { + case IKEV1_ENCAP_TRANSPORT: + return MODE_TRANSPORT; + case IKEV1_ENCAP_TUNNEL: + return MODE_TUNNEL; + case IKEV1_ENCAP_UDP_TRANSPORT: + *udp = TRUE; + return MODE_TRANSPORT; + case IKEV1_ENCAP_UDP_TUNNEL: + *udp = TRUE; + return MODE_TUNNEL; + default: + /* default to TUNNEL, RFC 2407 says implementation specific */ + return MODE_TUNNEL; + } +} + METHOD2(payload_t, proposal_substructure_t, destroy, void, private_proposal_substructure_t *this) { this->transforms->destroy_offset(this->transforms, - offsetof(transform_substructure_t, destroy)); + offsetof(payload_t, destroy)); chunk_free(&this->spi); free(this); } @@ -360,7 +1148,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void, /* * Described in header. */ -proposal_substructure_t *proposal_substructure_create() +proposal_substructure_t *proposal_substructure_create(payload_type_t type) { private_proposal_substructure_t *this; @@ -369,6 +1157,7 @@ proposal_substructure_t *proposal_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -380,39 +1169,197 @@ proposal_substructure_t *proposal_substructure_create() .set_protocol_id = _set_protocol_id, .get_protocol_id = _get_protocol_id, .set_is_last_proposal = _set_is_last_proposal, - .get_proposal = _get_proposal, + .get_proposals = _get_proposals, .create_substructure_enumerator = _create_substructure_enumerator, .set_spi = _set_spi, .get_spi = _get_spi, + .get_cpi = _get_cpi, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH, .transforms = linked_list_create(), + .type = type, ); + compute_length(this); return &this->public; } -/* - * Described in header. +/** + * Add an IKEv1 IKE proposal to the substructure */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - proposal_t *proposal) +static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, + proposal_t *proposal, u_int32_t lifetime, + auth_method_t method, int number) { transform_substructure_t *transform; - private_proposal_substructure_t *this; u_int16_t alg, key_size; enumerator_t *enumerator; - this = (private_proposal_substructure_t*)proposal_substructure_create(); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + number, IKEV1_TRANSID_KEY_IKE); + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_ENCRYPTION_ALGORITHM, alg)); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_KEY_LENGTH, key_size)); + } + } + } + enumerator->destroy(enumerator); + + /* encode the integrity algorithm as hash and assume use the same PRF */ + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_HASH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_GROUP, alg)); + } + enumerator->destroy(enumerator); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method))); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_DURATION, lifetime)); + + add_transform_substructure(this, transform); +} + +/** + * Add an IKEv1 ESP proposal to the substructure + */ +static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + ipsec_mode_t mode, bool udp, int number) +{ + transform_substructure_t *transform = NULL; + u_int16_t alg, key_size; + enumerator_t *enumerator; + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg); + if (alg) + { + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + number, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_KEY_LENGTH, key_size)); + } + } + } + enumerator->destroy(enumerator); + if (!transform) + { + return; + } + + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_AUTH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_GROUP, alg)); + } + enumerator->destroy(enumerator); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } + + add_transform_substructure(this, transform); +} + +/** + * Add an IKEv2 proposal to the substructure + */ +static void set_from_proposal_v2(private_proposal_substructure_t *this, + proposal_t *proposal) +{ + transform_substructure_t *transform; + u_int16_t alg, key_size; + enumerator_t *enumerator; /* encryption algorithm is only available in ESP */ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + ENCRYPTION_ALGORITHM, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE, + TATTR_IKEV2_KEY_LENGTH, key_size)); + } add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -421,8 +1368,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + INTEGRITY_ALGORITHM, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -431,8 +1378,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + PSEUDO_RANDOM_FUNCTION, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -441,8 +1388,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, - alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + DIFFIE_HELLMAN_GROUP, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -451,27 +1398,36 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, - alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + EXTENDED_SEQUENCE_NUMBERS, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); +} + +/** + * Set SPI and other data from proposal, compute length + */ +static void set_data(private_proposal_substructure_t *this, proposal_t *proposal) +{ + u_int64_t spi64; + u_int32_t spi32; /* add SPI, if necessary */ switch (proposal->get_protocol(proposal)) { case PROTO_AH: case PROTO_ESP: - this->spi_size = this->spi.len = 4; - this->spi.ptr = malloc(this->spi_size); - *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal); + spi32 = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi32)); + this->spi_size = this->spi.len; break; case PROTO_IKE: - if (proposal->get_spi(proposal)) + spi64 = proposal->get_spi(proposal); + if (spi64) { /* IKE only uses SPIS when rekeying, but on initial setup */ - this->spi_size = this->spi.len = 8; - this->spi.ptr = malloc(this->spi_size); - *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi64)); + this->spi_size = this->spi.len; } break; default: @@ -480,6 +1436,144 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( this->proposal_number = proposal->get_number(proposal); this->protocol_id = proposal->get_protocol(proposal); compute_length(this); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(SECURITY_ASSOCIATION); + set_from_proposal_v2(this, proposal); + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, auth, 1); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, 1); + break; + default: + break; + } + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this = NULL; + enumerator_t *enumerator; + proposal_t *proposal; + int number = 0; + + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (!this) + { + this = (private_proposal_substructure_t*) + proposal_substructure_create_from_proposal_v1( + proposal, lifetime, lifebytes, auth, mode, udp); + ++number; + } + else + { + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, + auth, ++number); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, ++number); + break; + default: + break; + } + } + } + enumerator->destroy(enumerator); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1( + u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi, + ipsec_mode_t mode, bool udp, u_int8_t proposal_number) +{ + private_proposal_substructure_t *this; + transform_substructure_t *transform; + + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + + /* we currently support DEFLATE only */ + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + 1, IKEV1_IPCOMP_DEFLATE); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } + + add_transform_substructure(this, transform); + + this->spi = chunk_clone(chunk_from_thing(cpi)); + this->spi_size = this->spi.len; + this->protocol_id = PROTO_IPCOMP; + this->proposal_number = proposal_number; + + compute_length(this); return &this->public; } diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index d0ba1fd2a..5d42a6116 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -29,17 +30,11 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include #include #include - +#include +#include /** - * Length of the proposal substructure header (without spi). - */ -#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. - * - * The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1. + * Class representing an IKEv1/IKEv2 proposal substructure. */ struct proposal_substructure_t { @@ -58,7 +53,7 @@ struct proposal_substructure_t { /** * get proposal number of current proposal. * - * @return proposal number of current proposal substructure. + * @return proposal number of current proposal substructure. */ u_int8_t (*get_proposal_number) (proposal_substructure_t *this); @@ -73,7 +68,7 @@ struct proposal_substructure_t { /** * get protocol id of current proposal. * - * @return protocol id of current proposal substructure. + * @return protocol id of current proposal substructure. */ u_int8_t (*get_protocol_id) (proposal_substructure_t *this); @@ -90,7 +85,7 @@ struct proposal_substructure_t { /** * Returns the currently set SPI of this proposal. * - * @return chunk_t pointing to the value + * @return chunk_t pointing to the value */ chunk_t (*get_spi) (proposal_substructure_t *this); @@ -104,11 +99,19 @@ struct proposal_substructure_t { void (*set_spi) (proposal_substructure_t *this, chunk_t spi); /** - * Get a proposal_t from the propsal_substructure_t. + * Gets the CPI of the current proposal (IKEv1 only). + * + * @param cpi the CPI if a supported algorithm is proposed + * @return TRUE if a supported algorithm is proposed + */ + bool (*get_cpi) (proposal_substructure_t *this, u_int16_t *cpi); + + /** + * Get proposals contained in a propsal_substructure_t. * - * @return proposal_t + * @param list list to add created proposals to */ - proposal_t * (*get_proposal) (proposal_substructure_t *this); + void (*get_proposals) (proposal_substructure_t *this, linked_list_t *list); /** * Create an enumerator over transform substructures. @@ -117,6 +120,35 @@ struct proposal_substructure_t { */ enumerator_t* (*create_substructure_enumerator)(proposal_substructure_t *this); + /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(proposal_substructure_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(proposal_substructure_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). + * + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(proposal_substructure_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(proposal_substructure_t *this, bool *udp); + /** * Destroys an proposal_substructure_t object. */ @@ -126,17 +158,63 @@ struct proposal_substructure_t { /** * Creates an empty proposal_substructure_t object * - * @return proposal_substructure_t object + * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + * @return proposal_substructure_t object */ -proposal_substructure_t *proposal_substructure_create(void); +proposal_substructure_t *proposal_substructure_create(payload_type_t type); /** - * Creates a proposal_substructure_t from a proposal_t. + * Creates an IKEv2 proposal_substructure_t from a proposal_t. * - * @param proposal proposal to build a substruct out of it - * @return proposal_substructure_t object + * @param proposal proposal to build a substruct out of it + * @return proposal_substructure_t PROPOSAL_SUBSTRUCTURE */ -proposal_substructure_t *proposal_substructure_create_from_proposal( +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( proposal_t *proposal); +/** + * Creates an IKEv1 proposal_substructure_t from a proposal_t. + * + * @param proposal proposal to build a substruct out of it + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 proposal_substructure_t from a list of proposal_t. + * + * @param proposals list of proposal_t to encode in a substructure + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 proposal_substructure_t for IPComp with the given + * proposal_number (e.g. of a ESP proposal to bundle them). + * + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param cpi the CPI to be used + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param proposal_number the proposal number of the proposal to be linked + * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1( + u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi, + ipsec_mode_t mode, bool udp, u_int8_t proposal_number); #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 010f63cfd..adf19aa67 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -22,6 +23,8 @@ #include #include +/* IKEv1 situation */ +#define SIT_IDENTITY_ONLY 1 typedef struct private_sa_payload_t private_sa_payload_t; @@ -48,7 +51,7 @@ struct private_sa_payload_t { /** * Reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -58,21 +61,75 @@ struct private_sa_payload_t { /** * Proposals in this payload are stored in a linked_list_t. */ - linked_list_t * proposals; + linked_list_t *proposals; + + /** + * Type of this payload, V1 or V2 + */ + payload_type_t type; + + /** + * IKEv1 DOI + */ + u_int32_t doi; + + /** + * IKEv1 situation + */ + u_int32_t situation; }; /** - * Encoding rules to parse or generate a IKEv2-SA Payload - * - * The defined offsets are the positions in a object of type - * private_sa_payload_t. + * Encoding rules for IKEv1 SA payload */ -encoding_rule_t sa_payload_encodings[] = { +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) }, + /* Length of the whole SA payload*/ + { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, + /* DOI*/ + { U_INT_32, offsetof(private_sa_payload_t, doi) }, + /* Situation*/ + { U_INT_32, offsetof(private_sa_payload_t, situation) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1, + offsetof(private_sa_payload_t, proposals) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Situation ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for IKEv2 SA payload + */ +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, /* the critical bit */ { FLAG, offsetof(private_sa_payload_t, critical) }, - /* 7 Bit reserved bits, nowhere stored */ + /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, @@ -82,9 +139,9 @@ encoding_rule_t sa_payload_encodings[] = { { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, /* Length of the whole SA payload*/ { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { PROPOSALS, offsetof(private_sa_payload_t, proposals) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE, + offsetof(private_sa_payload_t, proposals) }, }; /* @@ -102,11 +159,16 @@ encoding_rule_t sa_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_sa_payload_t *this) { - int expected_number = 1, current_number; + int expected_number = 0, current_number; status_t status = SUCCESS; enumerator_t *enumerator; proposal_substructure_t *substruct; + if (this->type == SECURITY_ASSOCIATION) + { + expected_number = 1; + } + /* check proposal numbering */ enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void**)&substruct)) @@ -131,17 +193,32 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_sa_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == SECURITY_ASSOCIATION_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); +} + +METHOD(payload_t, get_header_length, int, + private_sa_payload_t *this) { - *rules = sa_payload_encodings; - *rule_count = countof(sa_payload_encodings); + if (this->type == SECURITY_ASSOCIATION_V1) + { + return 12; + } + return 4; } METHOD(payload_t, get_type, payload_type_t, private_sa_payload_t *this) { - return SECURITY_ASSOCIATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -163,16 +240,15 @@ static void compute_length(private_sa_payload_t *this) { enumerator_t *enumerator; payload_t *current; - size_t length = SA_PAYLOAD_HEADER_LENGTH; + + this->payload_length = get_header_length(this); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void **)¤t)) { - length += current->get_length(current); + this->payload_length += current->get_length(current); } enumerator->destroy(enumerator); - - this->payload_length = length; } METHOD(payload_t, get_length, size_t, @@ -181,14 +257,16 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } -METHOD(sa_payload_t, add_proposal, void, - private_sa_payload_t *this, proposal_t *proposal) +/** + * Create a transform substructure from a proposal, add to payload + */ +static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; u_int count; + substruct = proposal_substructure_create_from_proposal_v2(proposal); count = this->proposals->get_count(this->proposals); - substruct = proposal_substructure_create_from_proposal(proposal); if (count > 0) { this->proposals->get_last(this->proposals, (void**)&last); @@ -215,15 +293,19 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, int ignore_struct_number = 0; enumerator_t *enumerator; proposal_substructure_t *substruct; - linked_list_t *list; - proposal_t *proposal; + linked_list_t *substructs, *list; + + if (this->type == SECURITY_ASSOCIATION_V1) + { /* IKEv1 proposals start with 0 */ + struct_number = ignore_struct_number = -1; + } - list = linked_list_create(); /* we do not support proposals split up to two proposal substructures, as * AH+ESP bundles are not supported in RFC4301 anymore. * To handle such structures safely, we just skip proposals with multiple * protocols. */ + substructs = linked_list_create(); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, &substruct)) { @@ -231,22 +313,80 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, if (substruct->get_proposal_number(substruct) == struct_number) { if (ignore_struct_number < struct_number) - { - /* remove an already added, if first of series */ - list->remove_last(list, (void**)&proposal); - proposal->destroy(proposal); + { /* remove an already added, if first of series */ + substructs->remove_last(substructs, (void**)&substruct); ignore_struct_number = struct_number; } continue; } struct_number++; - proposal = substruct->get_proposal(substruct); - if (proposal) + substructs->insert_last(substructs, substruct); + } + enumerator->destroy(enumerator); + + /* generate proposals from substructs */ + list = linked_list_create(); + enumerator = substructs->create_enumerator(substructs); + while (enumerator->enumerate(enumerator, &substruct)) + { + substruct->get_proposals(substruct, list); + } + enumerator->destroy(enumerator); + substructs->destroy(substructs); + return list; +} + +METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*, + private_sa_payload_t *this, u_int16_t *cpi) +{ + int current_proposal = -1, unsupported_proposal = -1; + enumerator_t *enumerator; + proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL; + linked_list_t *list; + + /* we currently only support the combination ESP+IPComp, find the first */ + enumerator = this->proposals->create_enumerator(this->proposals); + while (enumerator->enumerate(enumerator, &substruct)) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + u_int8_t protocol_id = substruct->get_protocol_id(substruct); + + if (proposal_number == unsupported_proposal) + { + continue; + } + if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP) + { /* unsupported combination */ + esp = ipcomp = NULL; + unsupported_proposal = current_proposal; + continue; + } + if (proposal_number != current_proposal) + { /* start of a new proposal */ + if (esp && ipcomp) + { /* previous proposal is valid */ + break; + } + esp = ipcomp = NULL; + current_proposal = proposal_number; + } + switch (protocol_id) { - list->insert_last(list, proposal); + case PROTO_ESP: + esp = substruct; + break; + case PROTO_IPCOMP: + ipcomp = substruct; + break; } } enumerator->destroy(enumerator); + + list = linked_list_create(); + if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi)) + { + esp->get_proposals(esp, list); + } return list; } @@ -256,18 +396,86 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, return this->proposals->create_enumerator(this->proposals); } +METHOD(sa_payload_t, get_lifetime, u_int32_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int32_t lifetime = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifetime = substruct->get_lifetime(substruct); + } + enumerator->destroy(enumerator); + + return lifetime; +} + +METHOD(sa_payload_t, get_lifebytes, u_int64_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int64_t lifebytes = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifebytes = substruct->get_lifebytes(substruct); + } + enumerator->destroy(enumerator); + + return lifebytes; +} + +METHOD(sa_payload_t, get_auth_method, auth_method_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + auth_method_t method = AUTH_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + method = substruct->get_auth_method(substruct); + } + enumerator->destroy(enumerator); + + return method; +} + +METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, + private_sa_payload_t *this, bool *udp) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + ipsec_mode_t mode = MODE_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + mode = substruct->get_encap_mode(substruct, udp); + } + enumerator->destroy(enumerator); + + return mode; +} + METHOD2(payload_t, sa_payload_t, destroy, void, private_sa_payload_t *this) { this->proposals->destroy_offset(this->proposals, - offsetof(proposal_substructure_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -sa_payload_t *sa_payload_create() +sa_payload_t *sa_payload_create(payload_type_t type) { private_sa_payload_t *this; @@ -276,38 +484,49 @@ sa_payload_t *sa_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, - .add_proposal = _add_proposal, .get_proposals = _get_proposals, + .get_ipcomp_proposals = _get_ipcomp_proposals, .create_substructure_enumerator = _create_substructure_enumerator, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = SA_PAYLOAD_HEADER_LENGTH, .proposals = linked_list_create(), + .type = type, + /* for IKEv1 only */ + .doi = IKEV1_DOI_IPSEC, + .situation = SIT_IDENTITY_ONLY, ); + + compute_length(this); + return &this->public; } /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) { private_sa_payload_t *this; enumerator_t *enumerator; proposal_t *proposal; - this = (private_sa_payload_t*)sa_payload_create(); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + add_proposal_v2(this, proposal); } enumerator->destroy(enumerator); @@ -317,12 +536,71 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) +{ + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + add_proposal_v2(this, proposal); + + return &this->public; + +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi) { + proposal_substructure_t *substruct; private_sa_payload_t *this; - this = (private_sa_payload_t*)sa_payload_create(); - add_proposal(this, proposal); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); + + /* IKEv1 encodes multiple proposals in a single substructure + * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + if (cpi) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + + substruct = proposal_substructure_create_for_ipcomp_v1(lifetime, + lifebytes, cpi, mode, udp, proposal_number); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + /* add the proposals again without IPComp */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + substruct->set_proposal_number(substruct, proposal_number + 1); + this->proposals->insert_last(this->proposals, substruct); + } + substruct->set_is_last_proposal(substruct, TRUE); + compute_length(this); + + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi) +{ + private_sa_payload_t *this; + linked_list_t *proposals; + proposals = linked_list_create(); + proposals->insert_last(proposals, proposal); + this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp, cpi); + proposals->destroy(proposals); return &this->public; } diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index cc8c481c8..9a88cccd5 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -28,14 +28,11 @@ typedef struct sa_payload_t sa_payload_t; #include #include #include +#include +#include /** - * SA_PAYLOAD length in bytes without any proposal substructure. - */ -#define SA_PAYLOAD_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2-SA Payload. + * Class representing an IKEv1 or IKEv2 SA Payload. * * The SA Payload format is described in RFC section 3.3. */ @@ -49,16 +46,47 @@ struct sa_payload_t { /** * Gets the proposals in this payload as a list. * - * @return a list containing proposal_t s + * @return a list containing proposal_ts */ linked_list_t *(*get_proposals) (sa_payload_t *this); /** - * Add a child proposal (AH/ESP) to the payload. + * Gets the proposals from the first proposal in this payload with IPComp + * enabled (IKEv1 only). + * + * @param cpi the CPI of the first IPComp (sub)proposal + * @return a list containing proposal_ts + */ + linked_list_t *(*get_ipcomp_proposals) (sa_payload_t *this, u_int16_t *cpi); + + /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(sa_payload_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(sa_payload_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). * - * @param proposal child proposal to add to the payload + * @return auth method, or AUTH_NONE */ - void (*add_proposal) (sa_payload_t *this, proposal_t *proposal); + auth_method_t (*get_auth_method)(sa_payload_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(sa_payload_t *this, bool *udp); /** * Create an enumerator over all proposal substructures. @@ -76,27 +104,59 @@ struct sa_payload_t { /** * Creates an empty sa_payload_t object * + * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @return created sa_payload_t object */ -sa_payload_t *sa_payload_create(void); +sa_payload_t *sa_payload_create(payload_type_t type); /** - * Creates a sa_payload_t object from a list of proposals. + * Creates an IKEv2 sa_payload_t object from a list of proposals. * * @param proposals list of proposals to build the payload from * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals); +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals); /** - * Creates a sa_payload_t object from a single proposal. + * Creates an IKEv2 sa_payload_t object from a single proposal. * - * This is only for convenience. Use sa_payload_create_from_proposal_list - * if you want to add more than one proposal. + * @param proposal proposal from which the payload should be built. + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal); + +/** + * Creates an IKEv1 sa_payload_t object from a list of proposals. + * + * @param proposals list of proposals to build the payload from + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param cpi CPI in case IPComp should be used + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi); + +/** + * Creates an IKEv1 sa_payload_t object from a single proposal. * * @param proposal proposal from which the payload should be built. + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param cpi CPI in case IPComp should be used * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal); +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi); #endif /** SA_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c index df36e4383..378f5bbc3 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.c +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c @@ -74,7 +74,7 @@ struct private_traffic_selector_substructure_t { * The defined offsets are the positions in a object of type * private_traffic_selector_substructure_t. */ -encoding_rule_t traffic_selector_substructure_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next ts type*/ { TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) }, /* 1 Byte IP protocol id*/ @@ -148,12 +148,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_traffic_selector_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_traffic_selector_substructure_t *this, encoding_rule_t **rules) { - *rules = traffic_selector_substructure_encodings; - *rule_count = countof(traffic_selector_substructure_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_traffic_selector_substructure_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -208,6 +213,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -217,7 +223,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .get_traffic_selector = _get_traffic_selector, .destroy = _destroy, }, - .payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH, + .payload_length = get_header_length(this), /* must be set to be valid */ .ts_type = TS_IPV4_ADDR_RANGE, ); @@ -239,7 +245,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff this->end_port = ts->get_to_port(ts); this->starting_address = chunk_clone(ts->get_from_address(ts)); this->ending_address = chunk_clone(ts->get_to_address(ts)); - this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + + this->payload_length = get_header_length(this) + this->ending_address.len + this->starting_address.len; return &this->public; diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.h b/src/libcharon/encoding/payloads/traffic_selector_substructure.h index 0109fd7f5..1ad5fb526 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.h +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.h @@ -29,11 +29,6 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t; #include #include -/** - * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address. - */ -#define TRAFFIC_SELECTOR_HEADER_LENGTH 8 - /** * Class representing an IKEv2 TRAFFIC SELECTOR. * diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 7d21258b1..d20f77c59 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -17,12 +17,51 @@ #include #include +#include #include "transform_attribute.h" #include #include +ENUM(tattr_ph1_names, TATTR_PH1_ENCRYPTION_ALGORITHM, TATTR_PH1_GROUP_ORDER, + "ENCRYPTION_ALGORITHM", + "HASH_ALGORITHM", + "AUTH_METHOD", + "GROUP", + "GROUP_TYPE", + "GROUP_PRIME", + "GROUP_GENONE", + "GROUP_GENTWO", + "GROUP_CURVE_A", + "GROUP_CURVE_B", + "LIFE_TYPE", + "LIFE_DURATION", + "PRF", + "KEY_LENGTH", + "FIELD_SIZE", + "GROUP_ORDER", +); + +ENUM(tattr_ph2_names, TATTR_PH2_SA_LIFE_TYPE, TATTR_PH2_EXT_SEQ_NUMBER, + "SA_LIFE_TYPE", + "SA_LIFE_DURATION", + "GROUP", + "ENCAP_MODE", + "AUTH_ALGORITHM", + "KEY_LENGTH", + "KEY_ROUNDS", + "COMP_DICT_SIZE", + "COMP_PRIV_ALGORITHM", + "ECN_TUNNEL", + "EXT_SEQ_NUMBER", +); + +ENUM(tattr_ikev2_names, TATTR_IKEV2_KEY_LENGTH, TATTR_IKEV2_KEY_LENGTH, + "KEY_LENGTH", +); + + typedef struct private_transform_attribute_t private_transform_attribute_t; /** @@ -57,30 +96,25 @@ struct private_transform_attribute_t { * Attribute value as chunk if attribute_format is 0 (FALSE). */ chunk_t attribute_value; -}; - -ENUM_BEGIN(transform_attribute_type_name, ATTRIBUTE_UNDEFINED, ATTRIBUTE_UNDEFINED, - "ATTRIBUTE_UNDEFINED"); -ENUM_NEXT(transform_attribute_type_name, KEY_LENGTH, KEY_LENGTH, ATTRIBUTE_UNDEFINED, - "KEY_LENGTH"); -ENUM_END(transform_attribute_type_name, KEY_LENGTH); + /** + * Payload type, TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + */ + payload_type_t type; +}; /** - * Encoding rules to parse or generate a Transform attribute. - * - * The defined offsets are the positions in a object of type - * private_transform_attribute_t. + * Encoding rules for IKEv1/IKEv2 transform attributes */ -encoding_rule_t transform_attribute_encodings[] = { +static encoding_rule_t encodings[] = { /* Flag defining the format of this payload */ - { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) }, + { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) }, /* type of the attribute as 15 bit unsigned integer */ { ATTRIBUTE_TYPE, offsetof(private_transform_attribute_t, attribute_type) }, /* Length or value, depending on the attribute format flag */ { ATTRIBUTE_LENGTH_OR_VALUE,offsetof(private_transform_attribute_t, attribute_length_or_value) }, /* Value of attribute if attribute format flag is zero */ - { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) } + { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) } }; /* @@ -101,18 +135,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_attribute_t *this, encoding_rule_t **rules) { - *rules = transform_attribute_encodings; - *rule_count = countof(transform_attribute_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_transform_attribute_t *this) +{ + return 0; } METHOD(payload_t, get_type, payload_type_t, private_transform_attribute_t *this) { - return TRANSFORM_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -136,31 +175,6 @@ METHOD(payload_t, get_length, size_t, return this->attribute_length_or_value + 4; } -METHOD(transform_attribute_t, set_value_chunk, void, - private_transform_attribute_t *this, chunk_t value) -{ - chunk_free(&this->attribute_value); - - if (value.len != 2) - { - this->attribute_value = chunk_clone(value); - this->attribute_length_or_value = value.len; - this->attribute_format = FALSE; - } - else - { - memcpy(&this->attribute_length_or_value, value.ptr, value.len); - } -} - -METHOD(transform_attribute_t, set_value, void, - private_transform_attribute_t *this, u_int16_t value) -{ - chunk_free(&this->attribute_value); - this->attribute_length_or_value = value; - this->attribute_format = TRUE; -} - METHOD(transform_attribute_t, get_value_chunk, chunk_t, private_transform_attribute_t *this) { @@ -171,16 +185,22 @@ METHOD(transform_attribute_t, get_value_chunk, chunk_t, return this->attribute_value; } -METHOD(transform_attribute_t, get_value, u_int16_t, +METHOD(transform_attribute_t, get_value, u_int64_t, private_transform_attribute_t *this) { - return this->attribute_length_or_value; -} + u_int64_t value = 0; -METHOD(transform_attribute_t, set_attribute_type, void, - private_transform_attribute_t *this, u_int16_t type) -{ - this->attribute_type = type & 0x7FFF; + if (this->attribute_format) + { + return this->attribute_length_or_value; + } + if (this->attribute_value.len > sizeof(value)) + { + return UINT64_MAX; + } + memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len, + this->attribute_value.ptr, this->attribute_value.len); + return untoh64((char*)&value); } METHOD(transform_attribute_t, get_attribute_type, u_int16_t, @@ -189,24 +209,6 @@ METHOD(transform_attribute_t, get_attribute_type, u_int16_t, return this->attribute_type; } -METHOD(transform_attribute_t, clone_, transform_attribute_t*, - private_transform_attribute_t *this) -{ - private_transform_attribute_t *new_clone; - - new_clone = (private_transform_attribute_t *)transform_attribute_create(); - - new_clone->attribute_format = this->attribute_format; - new_clone->attribute_type = this->attribute_type; - new_clone->attribute_length_or_value = this->attribute_length_or_value; - - if (!new_clone->attribute_format) - { - new_clone->attribute_value = chunk_clone(this->attribute_value); - } - return &new_clone->public; -} - METHOD2(payload_t, transform_attribute_t, destroy, void, private_transform_attribute_t *this) { @@ -217,7 +219,7 @@ METHOD2(payload_t, transform_attribute_t, destroy, void, /* * Described in header. */ -transform_attribute_t *transform_attribute_create() +transform_attribute_t *transform_attribute_create(payload_type_t type) { private_transform_attribute_t *this; @@ -226,22 +228,20 @@ transform_attribute_t *transform_attribute_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, - .set_value_chunk = _set_value_chunk, - .set_value = _set_value, .get_value_chunk = _get_value_chunk, .get_value = _get_value, - .set_attribute_type = _set_attribute_type, .get_attribute_type = _get_attribute_type, - .clone = _clone_, .destroy = _destroy, }, - .attribute_format = TRUE, + .attribute_format = FALSE, + .type = type, ); return &this->public; } @@ -249,10 +249,33 @@ transform_attribute_t *transform_attribute_create() /* * Described in header. */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length) +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int64_t value) { - transform_attribute_t *attribute = transform_attribute_create(); - attribute->set_attribute_type(attribute, KEY_LENGTH); - attribute->set_value(attribute, key_length); - return attribute; + private_transform_attribute_t *this; + + this = (private_transform_attribute_t*)transform_attribute_create(type); + + this->attribute_type = kind & 0x7FFF; + + if (value <= UINT16_MAX) + { + this->attribute_length_or_value = value; + this->attribute_format = TRUE; + } + else if (value <= UINT32_MAX) + { + u_int32_t val32; + + val32 = htonl(value); + this->attribute_value = chunk_clone(chunk_from_thing(val32)); + this->attribute_length_or_value = sizeof(val32); + } + else + { + htoun64(&value, value); + this->attribute_value = chunk_clone(chunk_from_thing(value)); + this->attribute_length_or_value = sizeof(value); + } + return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index a5fe0154b..23897a50a 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -28,26 +28,66 @@ typedef struct transform_attribute_t transform_attribute_t; #include #include - /** - * Type of the attribute, as in IKEv2 RFC 3.3.5. + * Type of the attribute. */ enum transform_attribute_type_t { - ATTRIBUTE_UNDEFINED = 16384, - KEY_LENGTH = 14 + /** IKEv1 Phase 1 attributes */ + TATTR_PH1_ENCRYPTION_ALGORITHM = 1, + TATTR_PH1_HASH_ALGORITHM = 2, + TATTR_PH1_AUTH_METHOD = 3, + TATTR_PH1_GROUP = 4, + TATTR_PH1_GROUP_TYPE = 5, + TATTR_PH1_GROUP_PRIME = 6, + TATTR_PH1_GROUP_GENONE = 7, + TATTR_PH1_GROUP_GENTWO = 8, + TATTR_PH1_GROUP_CURVE_A = 9, + TATTR_PH1_GROUP_CURVE_B = 10, + TATTR_PH1_LIFE_TYPE = 11, + TATTR_PH1_LIFE_DURATION = 12, + TATTR_PH1_PRF = 13, + TATTR_PH1_KEY_LENGTH = 14, + TATTR_PH1_FIELD_SIZE = 15, + TATTR_PH1_GROUP_ORDER = 16, + /** IKEv1 Phase 2 attributes */ + TATTR_PH2_SA_LIFE_TYPE = 1, + TATTR_PH2_SA_LIFE_DURATION = 2, + TATTR_PH2_GROUP = 3, + TATTR_PH2_ENCAP_MODE = 4, + TATTR_PH2_AUTH_ALGORITHM = 5, + TATTR_PH2_KEY_LENGTH = 6, + TATTR_PH2_KEY_ROUNDS = 7, + TATTR_PH2_COMP_DICT_SIZE = 8, + TATTR_PH2_COMP_PRIV_ALGORITHM = 9, + TATTR_PH2_ECN_TUNNEL = 10, + TATTR_PH2_EXT_SEQ_NUMBER = 11, + /* IKEv2 key length attribute */ + TATTR_IKEV2_KEY_LENGTH = 14, + /* undefined, private use attribute */ + TATTR_UNDEFINED = 16384, }; /** - * enum name for transform_attribute_type_t. + * Enum names for IKEv1 Phase 1 transform_attribute_type_t. */ -extern enum_name_t *transform_attribute_type_names; +extern enum_name_t *tattr_ph1_names; /** - * Class representing an IKEv2- TRANSFORM Attribute. - * - * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. + * Enum names for IKEv1 Phase 2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ph2_names; + +/** + * Enum names for IKEv2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ikev2_names; + + +/** + * Class representing an IKEv1/IKEv2 TRANSFORM Attribute. */ struct transform_attribute_t { + /** * The payload_t interface. */ @@ -58,7 +98,7 @@ struct transform_attribute_t { * * Returned data are not copied. * - * @return chunk_t pointing to the value + * @return chunk_t pointing to internal value */ chunk_t (*get_value_chunk) (transform_attribute_t *this); @@ -69,30 +109,7 @@ struct transform_attribute_t { * * @return value */ - u_int16_t (*get_value) (transform_attribute_t *this); - - /** - * Sets the value of the attribute. - * - * Value is getting copied. - * - * @param value chunk_t pointing to the value to set - */ - void (*set_value_chunk) (transform_attribute_t *this, chunk_t value); - - /** - * Sets the value of the attribute. - * - * @param value value to set - */ - void (*set_value) (transform_attribute_t *this, u_int16_t value); - - /** - * Sets the type of the attribute. - * - * @param type type to set (most significant bit is set to zero) - */ - void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type); + u_int64_t (*get_value) (transform_attribute_t *this); /** * get the type of the attribute. @@ -101,13 +118,6 @@ struct transform_attribute_t { */ u_int16_t (*get_attribute_type) (transform_attribute_t *this); - /** - * Clones an transform_attribute_t object. - * - * @return cloned transform_attribute_t object - */ - transform_attribute_t * (*clone) (transform_attribute_t *this); - /** * Destroys an transform_attribute_t object. */ @@ -117,16 +127,20 @@ struct transform_attribute_t { /** * Creates an empty transform_attribute_t object. * + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create(void); +transform_attribute_t *transform_attribute_create(payload_type_t type); /** - * Creates an transform_attribute_t of type KEY_LENGTH. + * Creates a two byte value or a larger attribute for a given attribute kind. * - * @param key_length key length in bytes + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + * @param kind attribute kind + * @param value fixed two byte value * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length); +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int64_t value); #endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 3f04b3539..a4a920b60 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -41,10 +41,11 @@ struct private_transform_substructure_t { * Next payload type. */ u_int8_t next_payload; + /** - * Reserved bytes + * Reserved byte */ - u_int8_t reserved[2]; + u_int8_t reserved[3]; /** * Length of this payload. @@ -52,43 +53,72 @@ struct private_transform_substructure_t { u_int16_t transform_length; /** - * Type of the transform. + * Type or number, Type of the transform in IKEv2, number in IKEv2. + */ + u_int8_t transform_ton; + + /** + * Transform ID, as encoded in IKEv1. */ - u_int8_t transform_type; + u_int8_t transform_id_v1; /** - * Transform ID. + * Transform ID, as encoded in IKEv2. */ - u_int16_t transform_id; + u_int16_t transform_id_v2; /** * Transforms Attributes are stored in a linked_list_t. */ linked_list_t *attributes; + + /** + * Payload type, TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a Transform substructure. - * - * The defined offsets are the positions in a object of type - * private_transform_substructure_t. + * Encoding rules for TRANSFORM_SUBSTRUCTURE */ -encoding_rule_t transform_substructure_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, /* Length of the whole transform substructure*/ - { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, - /* transform type is a number of 8 bit */ - { U_INT_8, offsetof(private_transform_substructure_t, transform_type) }, + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform type */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) }, + /* transform identifier, as used by IKEv1 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + /* transform identifier, as used by IKEv2 */ + { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) }, + /* Attributes in a transform attribute list */ + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE, + offsetof(private_transform_substructure_t, attributes) } +}; + +/** + * Encoding rules for TRANSFORM_SUBSTRUCTURE_V1 + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, - /* transform ID is a number of 8 bit */ - { U_INT_16, offsetof(private_transform_substructure_t, transform_id) }, - /* Attributes are stored in a transform attribute, - offset points to a linked_list_t pointer */ - { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) } + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + /* Length of the whole transform substructure*/ + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform number */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)}, + /* transform identifier, as used by IKEv1 */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) }, + /* transform identifier, as used by IKEv2 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) }, + /* Attributes in a transform attribute list */ + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1, + offsetof(private_transform_substructure_t, attributes) } }; /* @@ -97,7 +127,7 @@ encoding_rule_t transform_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! 0 (last) or 3 ! RESERVED ! Transform Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - !Transform Type ! RESERVED ! Transform ID ! + ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Transform Attributes ~ @@ -118,23 +148,6 @@ METHOD(payload_t, verify, status_t, return FAILED; } - switch (this->transform_type) - { - case ENCRYPTION_ALGORITHM: - case PSEUDO_RANDOM_FUNCTION: - case INTEGRITY_ALGORITHM: - case DIFFIE_HELLMAN_GROUP: - case EXTENDED_SEQUENCE_NUMBERS: - /* we don't check transform ID, we want to reply - * cleanly with NO_PROPOSAL_CHOSEN or so if we don't support it */ - break; - default: - { - DBG1(DBG_ENC, "invalid transform type: %d", this->transform_type); - return FAILED; - } - } - enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -151,18 +164,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_substructure_t *this, encoding_rule_t **rules) { - *rules = transform_substructure_encodings; - *rule_count = countof(transform_substructure_encodings); + if (this->type == TRANSFORM_SUBSTRUCTURE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_transform_substructure_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, private_transform_substructure_t *this) { - return TRANSFORM_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -174,12 +197,12 @@ METHOD(payload_t, get_next_type, payload_type_t, /** * recompute the length of the payload. */ -static void compute_length (private_transform_substructure_t *this) +static void compute_length(private_transform_substructure_t *this) { enumerator_t *enumerator; payload_t *attribute; - this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + this->transform_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -194,6 +217,13 @@ METHOD(payload_t, get_length, size_t, return this->transform_length; } +METHOD(transform_substructure_t, add_transform_attribute, void, + private_transform_substructure_t *this, transform_attribute_t *attribute) +{ + this->attributes->insert_last(this->attributes, attribute); + compute_length(this); +} + METHOD(transform_substructure_t, set_is_last_transform, void, private_transform_substructure_t *this, bool is_last) { @@ -205,50 +235,40 @@ METHOD(payload_t, set_next_type, void, { } -METHOD(transform_substructure_t, get_transform_type, u_int8_t, +METHOD(transform_substructure_t, get_transform_type_or_number, u_int8_t, private_transform_substructure_t *this) { - return this->transform_type; + return this->transform_ton; } METHOD(transform_substructure_t, get_transform_id, u_int16_t, private_transform_substructure_t *this) { - return this->transform_id; + if (this->type == TRANSFORM_SUBSTRUCTURE) + { + return this->transform_id_v2; + } + return this->transform_id_v1; } -METHOD(transform_substructure_t, get_key_length, status_t, - private_transform_substructure_t *this, u_int16_t *key_length) +METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*, + private_transform_substructure_t *this) { - enumerator_t *enumerator; - transform_attribute_t *attribute; - - enumerator = this->attributes->create_enumerator(this->attributes); - while (enumerator->enumerate(enumerator, &attribute)) - { - if (attribute->get_attribute_type(attribute) == KEY_LENGTH) - { - *key_length = attribute->get_value(attribute); - enumerator->destroy(enumerator); - return SUCCESS; - } - } - enumerator->destroy(enumerator); - return FAILED; + return this->attributes->create_enumerator(this->attributes); } METHOD2(payload_t, transform_substructure_t, destroy, void, private_transform_substructure_t *this) { this->attributes->destroy_offset(this->attributes, - offsetof(transform_attribute_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -transform_substructure_t *transform_substructure_create() +transform_substructure_t *transform_substructure_create(payload_type_t type) { private_transform_substructure_t *this; @@ -257,21 +277,24 @@ transform_substructure_t *transform_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, + .add_transform_attribute = _add_transform_attribute, .set_is_last_transform = _set_is_last_transform, - .get_transform_type = _get_transform_type, + .get_transform_type_or_number = _get_transform_type_or_number, .get_transform_id = _get_transform_id, - .get_key_length = _get_key_length, + .create_attribute_enumerator = _create_attribute_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH, + .transform_length = get_header_length(this), .attributes = linked_list_create(), + .type = type, ); return &this->public; } @@ -279,20 +302,21 @@ transform_substructure_t *transform_substructure_create() /* * Described in header */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length) +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id) { private_transform_substructure_t *this; - this = (private_transform_substructure_t*)transform_substructure_create(); + this = (private_transform_substructure_t*)transform_substructure_create(type); - this->transform_type = type; - this->transform_id = id; - if (key_length) + this->transform_ton = type_or_number; + if (type == TRANSFORM_SUBSTRUCTURE) + { + this->transform_id_v2 = id; + } + else { - this->attributes->insert_last(this->attributes, - (void*)transform_attribute_create_key_length(key_length)); - compute_length(this); + this->transform_id_v1 = id; } return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h index 102dbb3d3..947df24f9 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.h +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -40,14 +40,7 @@ typedef struct transform_substructure_t transform_substructure_t; #define TRANSFORM_TYPE_VALUE 3 /** - * Length of the transform substructure header in bytes. - */ -#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. - * - * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2. + * Class representing an IKEv1/IKEv2 transform substructure. */ struct transform_substructure_t { @@ -75,11 +68,11 @@ struct transform_substructure_t { void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); /** - * get transform type of the current transform. + * Get transform type (IKEv2) or the transform number (IKEv1). * * @return Transform type of current transform substructure. */ - u_int8_t (*get_transform_type) (transform_substructure_t *this); + u_int8_t (*get_transform_type_or_number) (transform_substructure_t *this); /** * Get transform id of the current transform. @@ -89,16 +82,11 @@ struct transform_substructure_t { u_int16_t (*get_transform_id) (transform_substructure_t *this); /** - * Get transform id of the current transform. + * Create an enumerator over transform attributes. * - * @param key_length The key length is written to this location - * @return - * - SUCCESS if a key length attribute is contained - * - FAILED if no key length attribute is part of this - * transform or key length uses more then 16 bit! + * @return enumerator over transform_attribute_t* */ - status_t (*get_key_length) (transform_substructure_t *this, - u_int16_t *key_length); + enumerator_t* (*create_attribute_enumerator)(transform_substructure_t *this); /** * Destroys an transform_substructure_t object. @@ -109,19 +97,20 @@ struct transform_substructure_t { /** * Creates an empty transform_substructure_t object. * + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 * @return created transform_substructure_t object */ -transform_substructure_t *transform_substructure_create(void); +transform_substructure_t *transform_substructure_create(payload_type_t type); /** * Creates an empty transform_substructure_t object. * - * @param type type of transform to create - * @param id transform id specifc for the transform type - * @param key_length key length for key length attribute, 0 to omit - * @return transform_substructure_t object + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + * @param type_or_number Type (IKEv2) or number (IKEv1) of transform + * @param id transform id specifc for the transform type + * @return transform_substructure_t object */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length); +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id); #endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c index 28f760e40..a7678da73 100644 --- a/src/libcharon/encoding/payloads/ts_payload.c +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -81,7 +81,7 @@ struct private_ts_payload_t { * The defined offsets are the positions in a object of type * private_ts_payload_t. */ -encoding_rule_t ts_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ts_payload_t, next_payload) }, /* the critical bit */ @@ -102,8 +102,9 @@ encoding_rule_t ts_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[2])}, - /* some ts data bytes, length is defined in PAYLOAD_LENGTH */ - { TRAFFIC_SELECTORS,offsetof(private_ts_payload_t, substrs) } + /* wrapped list of traffic selectors substructures */ + { PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE, + offsetof(private_ts_payload_t, substrs) }, }; /* @@ -145,11 +146,17 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ts_payload_t *this, encoding_rule_t **rules) { - *rules = ts_payload_encodings; - *rule_count = countof(ts_payload_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_ts_payload_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -182,7 +189,7 @@ static void compute_length(private_ts_payload_t *this) enumerator_t *enumerator; payload_t *subst; - this->payload_length = TS_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); this->ts_num = 0; enumerator = this->substrs->create_enumerator(this->substrs); while (enumerator->enumerate(enumerator, &subst)) @@ -250,6 +257,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -262,7 +270,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = TS_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .is_initiator = is_initiator, .substrs = linked_list_create(), ); diff --git a/src/libcharon/encoding/payloads/ts_payload.h b/src/libcharon/encoding/payloads/ts_payload.h index 88ca00bc9..5a92655dc 100644 --- a/src/libcharon/encoding/payloads/ts_payload.h +++ b/src/libcharon/encoding/payloads/ts_payload.h @@ -30,11 +30,6 @@ typedef struct ts_payload_t ts_payload_t; #include #include -/** - * Length of a TS payload without the Traffic selectors. - */ -#define TS_PAYLOAD_HEADER_LENGTH 8 - /** * Class representing an IKEv2 TS payload. * diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c index 27af338b3..fe7ced20b 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.c +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -68,7 +68,7 @@ struct private_unknown_payload_t { * private_unknown_payload_t. * */ -encoding_rule_t unknown_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_unknown_payload_t, next_payload) }, /* the critical bit */ @@ -84,7 +84,7 @@ encoding_rule_t unknown_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length) }, /* some unknown data bytes, length is defined in PAYLOAD_LENGTH */ - { UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) }, + { CHUNK_DATA, offsetof(private_unknown_payload_t, data) }, }; /* @@ -102,18 +102,20 @@ encoding_rule_t unknown_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_unknown_payload_t *this) { - if (this->payload_length != UNKNOWN_PAYLOAD_HEADER_LENGTH + this->data.len) - { - return FAILED; - } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_unknown_payload_t *this, encoding_rule_t **rules) { - *rules = unknown_payload_encodings; - *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_unknown_payload_t *this) +{ + return 4; } METHOD(payload_t, get_payload_type, payload_type_t, @@ -171,6 +173,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -182,7 +185,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .type = type, ); @@ -201,7 +204,7 @@ unknown_payload_t *unknown_payload_create_data(payload_type_t type, this = (private_unknown_payload_t*)unknown_payload_create(type); this->data = data; this->critical = critical; - this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH + data.len; + this->payload_length = get_header_length(this) + data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h index 5ae85331b..326b550cd 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.h +++ b/src/libcharon/encoding/payloads/unknown_payload.h @@ -27,11 +27,6 @@ typedef struct unknown_payload_t unknown_payload_t; #include #include -/** - * Header length of the unknown payload. - */ -#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4 - /** * Payload which can't be processed further. * diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index e9e80e989..0c1df56e2 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -55,6 +55,11 @@ struct private_vendor_id_payload_t { * The contained data. */ chunk_t data; + + /** + * Either a IKEv1 or a IKEv2 vendor ID payload + */ + payload_type_t type; }; /** @@ -63,7 +68,7 @@ struct private_vendor_id_payload_t { * The defined offsets are the positions in a object of type * private_vendor_id_payload_t. */ -encoding_rule_t vendor_id_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) }, /* the critical bit */ @@ -79,7 +84,7 @@ encoding_rule_t vendor_id_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)}, /* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */ - { VID_DATA, offsetof(private_vendor_id_payload_t, data) } + { CHUNK_DATA, offsetof(private_vendor_id_payload_t, data) } }; /* @@ -100,18 +105,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_vendor_id_payload_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_vendor_id_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_vendor_id_payload_t *this) { - *rules = vendor_id_payload_encodings; - *rule_count = countof(vendor_id_payload_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_vendor_id_payload_t *this) { - return VENDOR_ID; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -148,7 +158,8 @@ METHOD2(payload_t, vendor_id_payload_t, destroy, void, /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data) { private_vendor_id_payload_t *this; @@ -157,6 +168,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -167,8 +179,9 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + data.len, + .payload_length = get_header_length(this) + data.len, .data = data, + .type = type, ); return &this->public; } @@ -176,7 +189,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create() +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type) { - return vendor_id_payload_create_data(chunk_empty); + return vendor_id_payload_create_data(type, chunk_empty); } diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h index 4e4e7d8eb..9a814777b 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.h +++ b/src/libcharon/encoding/payloads/vendor_id_payload.h @@ -28,12 +28,7 @@ typedef struct vendor_id_payload_t vendor_id_payload_t; #include /** - * Length of a VENDOR ID payload without the VID data in bytes. - */ -#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2 VENDOR ID payload. + * Class representing an IKEv1/IKEv2 VENDOR ID payload. * * The VENDOR ID payload format is described in RFC section 3.12. */ @@ -58,18 +53,21 @@ struct vendor_id_payload_t { }; /** - * Creates an empty Vendor ID payload. + * Creates an empty Vendor ID payload for IKEv1 or IKEv2. * + * @@param type VENDOR_ID or VENDOR_ID_V1 * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create(); +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type); /** * Creates a vendor ID payload using a chunk of data * + * @param type VENDOR_ID or VENDOR_ID_V1 * @param data data to use in vendor ID payload, gets owned by payload * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data); +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data); #endif /** VENDOR_ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/kernel/kernel_handler.c b/src/libcharon/kernel/kernel_handler.c index 51fccb1ac..aa5c4e059 100644 --- a/src/libcharon/kernel/kernel_handler.c +++ b/src/libcharon/kernel/kernel_handler.c @@ -84,7 +84,7 @@ METHOD(kernel_listener_t, expire, bool, protocol_id_names, proto, ntohl(spi), reqid); if (hard) { - job = (job_t*)delete_child_sa_job_create(reqid, proto, spi); + job = (job_t*)delete_child_sa_job_create(reqid, proto, spi, hard); } else { diff --git a/src/libcharon/network/packet.c b/src/libcharon/network/packet.c deleted file mode 100644 index 19db362f7..000000000 --- a/src/libcharon/network/packet.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "packet.h" - -typedef struct private_packet_t private_packet_t; - -/** - * Private data of an packet_t object. - */ -struct private_packet_t { - - /** - * Public part of a packet_t object. - */ - packet_t public; - - /** - * source address - */ - host_t *source; - - /** - * destination address - */ - host_t *destination; - - /** - * message data - */ - chunk_t data; -}; - -METHOD(packet_t, set_source, void, - private_packet_t *this, host_t *source) -{ - DESTROY_IF(this->source); - this->source = source; -} - -METHOD(packet_t, set_destination, void, - private_packet_t *this, host_t *destination) -{ - DESTROY_IF(this->destination); - this->destination = destination; -} - -METHOD(packet_t, get_source, host_t*, - private_packet_t *this) -{ - return this->source; -} - -METHOD(packet_t, get_destination, host_t*, - private_packet_t *this) -{ - return this->destination; -} - -METHOD(packet_t, get_data, chunk_t, - private_packet_t *this) -{ - return this->data; -} - -METHOD(packet_t, set_data, void, - private_packet_t *this, chunk_t data) -{ - free(this->data.ptr); - this->data = data; -} - -METHOD(packet_t, destroy, void, - private_packet_t *this) -{ - DESTROY_IF(this->source); - DESTROY_IF(this->destination); - free(this->data.ptr); - free(this); -} - -METHOD(packet_t, clone_, packet_t*, - private_packet_t *this) -{ - packet_t *other; - - other = packet_create(); - if (this->destination != NULL) - { - other->set_destination(other, this->destination->clone(this->destination)); - } - if (this->source != NULL) - { - other->set_source(other, this->source->clone(this->source)); - } - if (this->data.ptr != NULL) - { - other->set_data(other, chunk_clone(this->data)); - } - return other; -} - -/* - * Documented in header - */ -packet_t *packet_create(void) -{ - private_packet_t *this; - - INIT(this, - .public = { - .set_data = _set_data, - .get_data = _get_data, - .set_source = _set_source, - .get_source = _get_source, - .set_destination = _set_destination, - .get_destination = _get_destination, - .clone = _clone_, - .destroy = _destroy, - }, - ); - - return &this->public; -} - diff --git a/src/libcharon/network/packet.h b/src/libcharon/network/packet.h deleted file mode 100644 index 18d82c6fc..000000000 --- a/src/libcharon/network/packet.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup packet packet - * @{ @ingroup network - */ - -#ifndef PACKET_H_ -#define PACKET_H_ - -typedef struct packet_t packet_t; - -#include -#include - -/** - * Abstraction of an UDP-Packet, contains data, sender and receiver. - */ -struct packet_t { - - /** - * Set the source address. - * - * Set host_t is now owned by packet_t, it will destroy - * it if necessary. - * - * @param source address to set as source - */ - void (*set_source) (packet_t *packet, host_t *source); - - /** - * Set the destination address. - * - * Set host_t is now owned by packet_t, it will destroy - * it if necessary. - * - * @param source address to set as destination - */ - void (*set_destination) (packet_t *packet, host_t *destination); - - /** - * Get the source address. - * - * Set host_t is still owned by packet_t, clone it - * if needed. - * - * @return source address - */ - host_t *(*get_source) (packet_t *packet); - - /** - * Get the destination address. - * - * Set host_t is still owned by packet_t, clone it - * if needed. - * - * @return destination address - */ - host_t *(*get_destination) (packet_t *packet); - - /** - * Get the data from the packet. - * - * The data pointed by the chunk is still owned - * by the packet. Clone it if needed. - * - * @return chunk containing the data - */ - chunk_t (*get_data) (packet_t *packet); - - /** - * Set the data in the packet. - * - * Supplied chunk data is now owned by the - * packet. It will free it. - * - * @param data chunk with data to set - */ - void (*set_data) (packet_t *packet, chunk_t data); - - /** - * Clones a packet_t object. - * - * @param clone clone of the packet - */ - packet_t* (*clone) (packet_t *packet); - - /** - * Destroy the packet, freeing contained data. - */ - void (*destroy) (packet_t *packet); -}; - -/** - * create an empty packet - * - * @return packet_t object - */ -packet_t *packet_create(void); - -#endif /** PACKET_H_ @}*/ diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index cfb1408ef..2f87a5ecb 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -20,13 +20,15 @@ #include "receiver.h" +#include #include #include -#include #include #include #include #include +#include +#include /** lifetime of a cookie, in seconds */ #define COOKIE_LIFETIME 10 @@ -40,6 +42,8 @@ #define BLOCK_THRESHOLD_DEFAULT 5 /** length of the secret to use for cookie calculation */ #define SECRET_LENGTH 16 +/** Length of a notify payload header */ +#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 typedef struct private_receiver_t private_receiver_t; @@ -53,9 +57,17 @@ struct private_receiver_t { receiver_t public; /** - * Threads job receiving packets + * Registered callback for ESP packets */ - callback_job_t *job; + struct { + receiver_esp_cb_t cb; + void *data; + } esp_cb; + + /** + * Mutex for ESP callback + */ + mutex_t *esp_cb_mutex; /** * current secret to use for cookie calculation @@ -141,41 +153,41 @@ struct private_receiver_t { /** * send a notify back to the sender */ -static void send_notify(message_t *request, notify_type_t type, chunk_t data) +static void send_notify(message_t *request, int major, exchange_type_t exchange, + notify_type_t type, chunk_t data) { - if (request->get_request(request) && - request->get_exchange_type(request) == IKE_SA_INIT) + ike_sa_id_t *ike_sa_id; + message_t *response; + host_t *src, *dst; + packet_t *packet; + + response = message_create(major, 0); + response->set_exchange_type(response, exchange); + response->add_notify(response, FALSE, type, data); + dst = request->get_source(request); + src = request->get_destination(request); + response->set_source(response, src->clone(src)); + response->set_destination(response, dst->clone(dst)); + if (major == IKEV2_MAJOR_VERSION) { - message_t *response; - host_t *src, *dst; - packet_t *packet; - ike_sa_id_t *ike_sa_id; - - response = message_create(); - dst = request->get_source(request); - src = request->get_destination(request); - response->set_source(response, src->clone(src)); - response->set_destination(response, dst->clone(dst)); - response->set_exchange_type(response, request->get_exchange_type(request)); response->set_request(response, FALSE); - response->set_message_id(response, 0); - ike_sa_id = request->get_ike_sa_id(request); - ike_sa_id->switch_initiator(ike_sa_id); - response->set_ike_sa_id(response, ike_sa_id); - response->add_notify(response, FALSE, type, data); - if (response->generate(response, NULL, &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet); - response->destroy(response); - } } + response->set_message_id(response, 0); + ike_sa_id = request->get_ike_sa_id(request); + ike_sa_id->switch_initiator(ike_sa_id); + response->set_ike_sa_id(response, ike_sa_id); + if (response->generate(response, NULL, &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); } /** * build a cookie */ -static chunk_t cookie_build(private_receiver_t *this, message_t *message, - u_int32_t t, chunk_t secret) +static bool cookie_build(private_receiver_t *this, message_t *message, + u_int32_t t, chunk_t secret, chunk_t *cookie) { u_int64_t spi = message->get_initiator_spi(message); host_t *ip = message->get_source(message); @@ -185,8 +197,12 @@ static chunk_t cookie_build(private_receiver_t *this, message_t *message, input = chunk_cata("cccc", ip->get_address(ip), chunk_from_thing(spi), chunk_from_thing(t), secret); hash = chunk_alloca(this->hasher->get_hash_size(this->hasher)); - this->hasher->get_hash(this->hasher, input, hash.ptr); - return chunk_cat("cc", chunk_from_thing(t), hash); + if (!this->hasher->get_hash(this->hasher, input, hash.ptr)) + { + return FALSE; + } + *cookie = chunk_cat("cc", chunk_from_thing(t), hash); + return TRUE; } /** @@ -221,7 +237,10 @@ static bool cookie_verify(private_receiver_t *this, message_t *message, } /* compare own calculation against received */ - reference = cookie_build(this, message, t, secret); + if (!cookie_build(this, message, t, secret, &reference)) + { + return FALSE; + } if (chunk_equals(reference, cookie)) { chunk_free(&reference); @@ -308,29 +327,42 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) half_open = charon->ike_sa_manager->get_half_open_count( charon->ike_sa_manager, NULL); - /* check for cookies */ - if (cookie_required(this, half_open, now) && !check_cookie(this, message)) + /* check for cookies in IKEv2 */ + if (message->get_major_version(message) == IKEV2_MAJOR_VERSION && + cookie_required(this, half_open, now) && !check_cookie(this, message)) { chunk_t cookie; - cookie = cookie_build(this, message, now - this->secret_offset, - chunk_from_thing(this->secret)); DBG2(DBG_NET, "received packet from: %#H to %#H", message->get_source(message), message->get_destination(message)); + if (!cookie_build(this, message, now - this->secret_offset, + chunk_from_thing(this->secret), &cookie)) + { + return TRUE; + } DBG2(DBG_NET, "sending COOKIE notify to %H", message->get_source(message)); - send_notify(message, COOKIE, cookie); + send_notify(message, IKEV2_MAJOR_VERSION, IKE_SA_INIT, COOKIE, cookie); chunk_free(&cookie); if (++this->secret_used > COOKIE_REUSE) { - /* create new cookie */ + char secret[SECRET_LENGTH]; + DBG1(DBG_NET, "generating new cookie secret after %d uses", this->secret_used); - memcpy(this->secret_old, this->secret, SECRET_LENGTH); - this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); - this->secret_switch = now; - this->secret_used = 0; + if (this->rng->get_bytes(this->rng, SECRET_LENGTH, secret)) + { + memcpy(this->secret_old, this->secret, SECRET_LENGTH); + memcpy(this->secret, secret, SECRET_LENGTH); + memwipe(secret, SECRET_LENGTH); + this->secret_switch = now; + this->secret_used = 0; + } + else + { + DBG1(DBG_NET, "failed to allocated cookie secret, keeping old"); + } } return TRUE; } @@ -380,16 +412,18 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) */ static job_requeue_t receive_packets(private_receiver_t *this) { + ike_sa_id_t *id; packet_t *packet; message_t *message; + host_t *src, *dst; status_t status; + bool supported = TRUE; + chunk_t data, marker = chunk_from_chars(0x00, 0x00, 0x00, 0x00); /* read in a packet */ status = charon->socket->receive(charon->socket, &packet); if (status == NOT_SUPPORTED) { - /* the processor destroys this job */ - this->job = NULL; return JOB_REQUEUE_NONE; } else if (status != SUCCESS) @@ -398,6 +432,56 @@ static job_requeue_t receive_packets(private_receiver_t *this) return JOB_REQUEUE_FAIR; } + data = packet->get_data(packet); + if (data.len == 1 && data.ptr[0] == 0xFF) + { /* silently drop NAT-T keepalives */ + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + else if (data.len < marker.len) + { /* drop packets that are too small */ + DBG3(DBG_NET, "received packet is too short (%d bytes)", data.len); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + + dst = packet->get_destination(packet); + src = packet->get_source(packet); + if (!hydra->kernel_interface->all_interfaces_usable(hydra->kernel_interface) + && !hydra->kernel_interface->get_interface(hydra->kernel_interface, + dst, NULL)) + { + DBG3(DBG_NET, "received packet from %#H to %#H on ignored interface", + src, dst); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + + /* if neither source nor destination port is 500 we assume an IKE packet + * with Non-ESP marker or an ESP packet */ + if (dst->get_port(dst) != IKEV2_UDP_PORT && + src->get_port(src) != IKEV2_UDP_PORT) + { + if (memeq(data.ptr, marker.ptr, marker.len)) + { /* remove Non-ESP marker */ + packet->skip_bytes(packet, marker.len); + } + else + { /* this seems to be an ESP packet */ + this->esp_cb_mutex->lock(this->esp_cb_mutex); + if (this->esp_cb.cb) + { + this->esp_cb.cb(this->esp_cb.data, packet); + } + else + { + packet->destroy(packet); + } + this->esp_cb_mutex->unlock(this->esp_cb_mutex); + return JOB_REQUEUE_DIRECT; + } + } + /* parse message header */ message = message_create_from_packet(packet); if (message->parse_header(message) != SUCCESS) @@ -409,16 +493,50 @@ static job_requeue_t receive_packets(private_receiver_t *this) } /* check IKE major version */ - if (message->get_major_version(message) != IKE_MAJOR_VERSION) + switch (message->get_major_version(message)) { - DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " - "sending INVALID_MAJOR_VERSION", message->get_major_version(message), + case IKEV2_MAJOR_VERSION: +#ifndef USE_IKEV2 + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_request(message)) + { + send_notify(message, IKEV1_MAJOR_VERSION, INFORMATIONAL_V1, + INVALID_MAJOR_VERSION, chunk_empty); + supported = FALSE; + } +#endif /* USE_IKEV2 */ + break; + case IKEV1_MAJOR_VERSION: +#ifndef USE_IKEV1 + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) + { + send_notify(message, IKEV2_MAJOR_VERSION, INFORMATIONAL, + INVALID_MAJOR_VERSION, chunk_empty); + supported = FALSE; + } +#endif /* USE_IKEV1 */ + break; + default: +#ifdef USE_IKEV2 + send_notify(message, IKEV2_MAJOR_VERSION, INFORMATIONAL, + INVALID_MAJOR_VERSION, chunk_empty); +#endif /* USE_IKEV2 */ +#ifdef USE_IKEV1 + send_notify(message, IKEV1_MAJOR_VERSION, INFORMATIONAL_V1, + INVALID_MAJOR_VERSION, chunk_empty); +#endif /* USE_IKEV1 */ + supported = FALSE; + break; + } + if (!supported) + { + DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, sending " + "INVALID_MAJOR_VERSION", message->get_major_version(message), message->get_minor_version(message), packet->get_source(packet)); - send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); message->destroy(message); return JOB_REQUEUE_DIRECT; } - if (message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { @@ -428,6 +546,18 @@ static job_requeue_t receive_packets(private_receiver_t *this) return JOB_REQUEUE_DIRECT; } } + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) + { + id = message->get_ike_sa_id(message); + if (id->get_responder_spi(id) == 0 && + drop_ike_sa_init(this, message)) + { + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } + } + if (this->receive_delay) { if (this->receive_delay_type == 0 || @@ -450,15 +580,33 @@ static job_requeue_t receive_packets(private_receiver_t *this) return JOB_REQUEUE_DIRECT; } -METHOD(receiver_t, destroy, void, - private_receiver_t *this) +METHOD(receiver_t, add_esp_cb, void, + private_receiver_t *this, receiver_esp_cb_t callback, void *data) +{ + this->esp_cb_mutex->lock(this->esp_cb_mutex); + this->esp_cb.cb = callback; + this->esp_cb.data = data; + this->esp_cb_mutex->unlock(this->esp_cb_mutex); +} + +METHOD(receiver_t, del_esp_cb, void, + private_receiver_t *this, receiver_esp_cb_t callback) { - if (this->job) + this->esp_cb_mutex->lock(this->esp_cb_mutex); + if (this->esp_cb.cb == callback) { - this->job->cancel(this->job); + this->esp_cb.cb = NULL; + this->esp_cb.data = NULL; } + this->esp_cb_mutex->unlock(this->esp_cb_mutex); +} + +METHOD(receiver_t, destroy, void, + private_receiver_t *this) +{ this->rng->destroy(this->rng); this->hasher->destroy(this->hasher); + this->esp_cb_mutex->destroy(this->esp_cb_mutex); free(this); } @@ -472,53 +620,62 @@ receiver_t *receiver_create() INIT(this, .public = { + .add_esp_cb = _add_esp_cb, + .del_esp_cb = _del_esp_cb, .destroy = _destroy, }, + .esp_cb_mutex = mutex_create(MUTEX_TYPE_DEFAULT), .secret_switch = now, .secret_offset = random() % now, ); - if (lib->settings->get_bool(lib->settings, "charon.dos_protection", TRUE)) + if (lib->settings->get_bool(lib->settings, + "%s.dos_protection", TRUE, charon->name)) { this->cookie_threshold = lib->settings->get_int(lib->settings, - "charon.cookie_threshold", COOKIE_THRESHOLD_DEFAULT); + "%s.cookie_threshold", COOKIE_THRESHOLD_DEFAULT, charon->name); this->block_threshold = lib->settings->get_int(lib->settings, - "charon.block_threshold", BLOCK_THRESHOLD_DEFAULT); + "%s.block_threshold", BLOCK_THRESHOLD_DEFAULT, charon->name); } this->init_limit_job_load = lib->settings->get_int(lib->settings, - "charon.init_limit_job_load", 0); + "%s.init_limit_job_load", 0, charon->name); this->init_limit_half_open = lib->settings->get_int(lib->settings, - "charon.init_limit_half_open", 0); + "%s.init_limit_half_open", 0, charon->name); this->receive_delay = lib->settings->get_int(lib->settings, - "charon.receive_delay", 0); + "%s.receive_delay", 0, charon->name); this->receive_delay_type = lib->settings->get_int(lib->settings, - "charon.receive_delay_type", 0), + "%s.receive_delay_type", 0, charon->name), this->receive_delay_request = lib->settings->get_bool(lib->settings, - "charon.receive_delay_request", TRUE), - this->receive_delay_response = lib->settings->get_int(lib->settings, - "charon.receive_delay_response", TRUE), + "%s.receive_delay_request", TRUE, charon->name), + this->receive_delay_response = lib->settings->get_bool(lib->settings, + "%s.receive_delay_response", TRUE, charon->name), this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED); - if (this->hasher == NULL) + if (!this->hasher) { DBG1(DBG_NET, "creating cookie hasher failed, no hashers supported"); free(this); return NULL; } this->rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (this->rng == NULL) + if (!this->rng) { DBG1(DBG_NET, "creating cookie RNG failed, no RNG supported"); this->hasher->destroy(this->hasher); free(this); return NULL; } - this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); + if (!this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret)) + { + DBG1(DBG_NET, "creating cookie secret failed"); + destroy(this); + return NULL; + } memcpy(this->secret_old, this->secret, SECRET_LENGTH); - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_packets, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive_packets, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/network/receiver.h b/src/libcharon/network/receiver.h index 1d9d4871e..9e8edee45 100644 --- a/src/libcharon/network/receiver.h +++ b/src/libcharon/network/receiver.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -26,14 +27,27 @@ typedef struct receiver_t receiver_t; #include #include +#include + +/** + * Callback called for any received UDP encapsulated ESP packet. + * + * Implementation should be quick as the receiver doesn't receive any packets + * while calling this function. + * + * @param data data supplied during registration of the callback + * @param packet decapsulated ESP packet + */ +typedef void (*receiver_esp_cb_t)(void *data, packet_t *packet); /** * Receives packets from the socket and adds them to the job queue. * - * The receiver starts a thread, which reads on the blocking socket. A received - * packet is preparsed and a process_message_job is queued in the job queue. + * The receiver uses a callback job, which reads on the blocking socket. + * A received packet is preparsed and a process_message_job is queued in the + * job queue. * - * To endure DoS attacks, cookies are enabled when to many IKE_SAs are half + * To endure DoS attacks, cookies are enabled when too many IKE_SAs are half * open. The calculation of cookies is slightly different from the proposed * method in RFC4306. We do not include a nonce, because we think the advantage * we gain does not justify the overhead to parse the whole message. @@ -47,14 +61,32 @@ typedef struct receiver_t receiver_t; * secret is stored to allow a clean migration between secret changes. * * Further, the number of half-initiated IKE_SAs is limited per peer. This - * mades it impossible for a peer to flood the server with its real IP address. + * makes it impossible for a peer to flood the server with its real IP address. */ struct receiver_t { + /** + * Register a callback which is called for any incoming ESP packets. + * + * @note Only the last callback registered will receive any packets. + * + * @param callback callback to register + * @param data data provided to callback + */ + void (*add_esp_cb)(receiver_t *this, receiver_esp_cb_t callback, + void *data); + + /** + * Unregister a previously registered callback for ESP packets. + * + * @param callback previously registered callback + */ + void (*del_esp_cb)(receiver_t *this, receiver_esp_cb_t callback); + /** * Destroys a receiver_t object. */ - void (*destroy) (receiver_t *receiver); + void (*destroy)(receiver_t *this); }; /** diff --git a/src/libcharon/network/sender.c b/src/libcharon/network/sender.c index 4df930b15..059f24b39 100644 --- a/src/libcharon/network/sender.c +++ b/src/libcharon/network/sender.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -38,11 +39,6 @@ struct private_sender_t { */ sender_t public; - /** - * Sender threads job. - */ - callback_job_t *job; - /** * The packets are stored in a linked list */ @@ -84,11 +80,21 @@ struct private_sender_t { bool send_delay_response; }; +METHOD(sender_t, send_no_marker, void, + private_sender_t *this, packet_t *packet) +{ + this->mutex->lock(this->mutex); + this->list->insert_last(this->list, packet); + this->got->signal(this->got); + this->mutex->unlock(this->mutex); +} + METHOD(sender_t, send_, void, private_sender_t *this, packet_t *packet) { host_t *src, *dst; + /* if neither source nor destination port is 500 we add a Non-ESP marker */ src = packet->get_source(packet); dst = packet->get_destination(packet); DBG1(DBG_NET, "sending packet: from %#H to %#H", src, dst); @@ -114,16 +120,22 @@ METHOD(sender_t, send_, void, message->destroy(message); } - this->mutex->lock(this->mutex); - this->list->insert_last(this->list, packet); - this->got->signal(this->got); - this->mutex->unlock(this->mutex); + if (dst->get_port(dst) != IKEV2_UDP_PORT && + src->get_port(src) != IKEV2_UDP_PORT) + { + chunk_t data, marker = chunk_from_chars(0x00, 0x00, 0x00, 0x00); + + data = chunk_cat("cc", marker, packet->get_data(packet)); + packet->set_data(packet, data); + } + + send_no_marker(this, packet); } /** * Job callback function to send packets */ -static job_requeue_t send_packets(private_sender_t * this) +static job_requeue_t send_packets(private_sender_t *this) { packet_t *packet; bool oldstate; @@ -149,7 +161,7 @@ static job_requeue_t send_packets(private_sender_t * this) return JOB_REQUEUE_DIRECT; } -METHOD(sender_t, destroy, void, +METHOD(sender_t, flush, void, private_sender_t *this) { /* send all packets in the queue */ @@ -159,8 +171,12 @@ METHOD(sender_t, destroy, void, this->sent->wait(this->sent, this->mutex); } this->mutex->unlock(this->mutex); - this->job->cancel(this->job); - this->list->destroy(this->list); +} + +METHOD(sender_t, destroy, void, + private_sender_t *this) +{ + this->list->destroy_offset(this->list, offsetof(packet_t, destroy)); this->got->destroy(this->got); this->sent->destroy(this->sent); this->mutex->destroy(this->mutex); @@ -177,25 +193,27 @@ sender_t * sender_create() INIT(this, .public = { .send = _send_, + .send_no_marker = _send_no_marker, + .flush = _flush, .destroy = _destroy, }, .list = linked_list_create(), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .got = condvar_create(CONDVAR_TYPE_DEFAULT), .sent = condvar_create(CONDVAR_TYPE_DEFAULT), - .job = callback_job_create_with_prio((callback_job_cb_t)send_packets, - this, NULL, NULL, JOB_PRIO_CRITICAL), .send_delay = lib->settings->get_int(lib->settings, - "charon.send_delay", 0), + "%s.send_delay", 0, charon->name), .send_delay_type = lib->settings->get_int(lib->settings, - "charon.send_delay_type", 0), + "%s.send_delay_type", 0, charon->name), .send_delay_request = lib->settings->get_bool(lib->settings, - "charon.send_delay_request", TRUE), - .send_delay_response = lib->settings->get_int(lib->settings, - "charon.send_delay_response", TRUE), + "%s.send_delay_request", TRUE, charon->name), + .send_delay_response = lib->settings->get_bool(lib->settings, + "%s.send_delay_response", TRUE, charon->name), ); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)send_packets, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/network/sender.h b/src/libcharon/network/sender.h index f77fadab2..9b5c325cc 100644 --- a/src/libcharon/network/sender.h +++ b/src/libcharon/network/sender.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,10 +26,10 @@ typedef struct sender_t sender_t; #include -#include +#include /** - * Thread responsible for sending packets over the socket. + * Callback job responsible for sending IKE packets over the socket. */ struct sender_t { @@ -43,6 +44,20 @@ struct sender_t { */ void (*send) (sender_t *this, packet_t *packet); + /** + * The same as send() but does not add Non-ESP markers automatically. + * + * @param packet packet to send + */ + void (*send_no_marker) (sender_t *this, packet_t *packet); + + /** + * Enforce a flush of the send queue. + * + * This function blocks until all queued packets have been sent. + */ + void (*flush)(sender_t *this); + /** * Destroys a sender object. */ diff --git a/src/libcharon/network/socket.h b/src/libcharon/network/socket.h index be875035b..b8850c6ed 100644 --- a/src/libcharon/network/socket.h +++ b/src/libcharon/network/socket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -27,7 +27,7 @@ typedef struct socket_t socket_t; #include -#include +#include #include #include @@ -67,6 +67,14 @@ struct socket_t { */ status_t (*send) (socket_t *this, packet_t *packet); + /** + * Get the port this socket is listening on. + * + * @param nat_t TRUE to get the port used to float in case of NAT-T + * @return the port + */ + u_int16_t (*get_port) (socket_t *this, bool nat_t); + /** * Destroy a socket implementation. */ diff --git a/src/libcharon/network/socket_manager.c b/src/libcharon/network/socket_manager.c index 72a454301..d2736de8e 100644 --- a/src/libcharon/network/socket_manager.c +++ b/src/libcharon/network/socket_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2010-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -89,6 +89,19 @@ METHOD(socket_manager_t, sender, status_t, return status; } +METHOD(socket_manager_t, get_port, u_int16_t, + private_socket_manager_t *this, bool nat_t) +{ + u_int16_t port = 0; + this->lock->read_lock(this->lock); + if (this->socket) + { + port = this->socket->get_port(this->socket, nat_t); + } + this->lock->unlock(this->lock); + return port; +} + static void create_socket(private_socket_manager_t *this) { socket_constructor_t create; @@ -153,6 +166,7 @@ socket_manager_t *socket_manager_create() .public = { .send = _sender, .receive = _receiver, + .get_port = _get_port, .add_socket = _add_socket, .remove_socket = _remove_socket, .destroy = _destroy, diff --git a/src/libcharon/network/socket_manager.h b/src/libcharon/network/socket_manager.h index 94185d21c..1909d1f25 100644 --- a/src/libcharon/network/socket_manager.h +++ b/src/libcharon/network/socket_manager.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Tobias Brunner + * Copyright (C) 2010-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -52,6 +52,14 @@ struct socket_manager_t { */ status_t (*send) (socket_manager_t *this, packet_t *packet); + /** + * Get the port the registered socket is listening on. + * + * @param nat_t TRUE to get the port used to float in case of NAT-T + * @return the port, or 0, if no socket is registered + */ + u_int16_t (*get_port) (socket_manager_t *this, bool nat_t); + /** * Register a socket constructor. * diff --git a/src/libcharon/plugins/addrblock/Makefile.in b/src/libcharon/plugins/addrblock/Makefile.in index 3139e20b0..8673e6ecd 100644 --- a/src/libcharon/plugins/addrblock/Makefile.in +++ b/src/libcharon/plugins/addrblock/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_addrblock_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_addrblock_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_addrblock_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/android/Makefile.am b/src/libcharon/plugins/android/Makefile.am index b922ef4af..b10cd9527 100644 --- a/src/libcharon/plugins/android/Makefile.am +++ b/src/libcharon/plugins/android/Makefile.am @@ -14,7 +14,6 @@ libstrongswan_android_la_SOURCES = \ android_plugin.c android_plugin.h \ android_service.c android_service.h \ android_handler.c android_handler.h \ - android_logger.c android_logger.h \ android_creds.c android_creds.h libstrongswan_android_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/android/Makefile.in b/src/libcharon/plugins/android/Makefile.in index 50e5f638e..ebe6ebb4d 100644 --- a/src/libcharon/plugins/android/Makefile.in +++ b/src/libcharon/plugins/android/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -76,8 +77,7 @@ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_android_la_DEPENDENCIES = am_libstrongswan_android_la_OBJECTS = android_plugin.lo \ - android_service.lo android_handler.lo android_logger.lo \ - android_creds.lo + android_service.lo android_handler.lo android_creds.lo libstrongswan_android_la_OBJECTS = \ $(am_libstrongswan_android_la_OBJECTS) libstrongswan_android_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -86,7 +86,7 @@ libstrongswan_android_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_android_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_android_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -294,7 +299,6 @@ libstrongswan_android_la_SOURCES = \ android_plugin.c android_plugin.h \ android_service.c android_service.h \ android_handler.c android_handler.h \ - android_logger.c android_logger.h \ android_creds.c android_creds.h libstrongswan_android_la_LDFLAGS = -module -avoid-version @@ -384,7 +388,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_creds.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_handler.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_service.Plo@am__quote@ diff --git a/src/libcharon/plugins/android/android_handler.c b/src/libcharon/plugins/android/android_handler.c index a53962f16..f1d3045ca 100644 --- a/src/libcharon/plugins/android/android_handler.c +++ b/src/libcharon/plugins/android/android_handler.c @@ -196,7 +196,7 @@ METHOD(enumerator_t, enumerate_dns, bool, } METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, - android_handler_t *this, identification_t *id, host_t *vip) + android_handler_t *this, identification_t *id, linked_list_t *vips) { enumerator_t *enumerator; diff --git a/src/libcharon/plugins/android/android_logger.c b/src/libcharon/plugins/android/android_logger.c deleted file mode 100644 index f7624b2c7..000000000 --- a/src/libcharon/plugins/android/android_logger.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include "android_logger.h" - -#include -#include - -typedef struct private_android_logger_t private_android_logger_t; - -/** - * Private data of an android_logger_t object - */ -struct private_android_logger_t { - - /** - * Public interface - */ - android_logger_t public; - - /** - * logging level - */ - int level; - -}; - - -METHOD(listener_t, log_, bool, - private_android_logger_t *this, debug_t group, level_t level, - int thread, ike_sa_t* ike_sa, char *format, va_list args) -{ - if (level <= this->level) - { - int prio = level > 1 ? ANDROID_LOG_DEBUG : ANDROID_LOG_INFO; - char sgroup[16], buffer[8192]; - char *current = buffer, *next; - snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group); - vsnprintf(buffer, sizeof(buffer), format, args); - while (current) - { /* log each line separately */ - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - __android_log_print(prio, "charon", "%.2d[%s] %s\n", - thread, sgroup, current); - current = next; - } - } - /* always stay registered */ - return TRUE; -} - -METHOD(android_logger_t, destroy, void, - private_android_logger_t *this) -{ - free(this); -} - -/** - * Described in header. - */ -android_logger_t *android_logger_create() -{ - private_android_logger_t *this; - - INIT(this, - .public = { - .listener = { - .log = _log_, - }, - .destroy = _destroy, - }, - .level = lib->settings->get_int(lib->settings, - "charon.plugins.android.loglevel", 1), - ); - - return &this->public; -} - diff --git a/src/libcharon/plugins/android/android_logger.h b/src/libcharon/plugins/android/android_logger.h deleted file mode 100644 index c6fe5aff3..000000000 --- a/src/libcharon/plugins/android/android_logger.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup android_logger android_logger - * @{ @ingroup android - */ - -#ifndef ANDROID_LOGGER_H_ -#define ANDROID_LOGGER_H_ - -#include - -typedef struct android_logger_t android_logger_t; - -/** - * Android specific logger. - */ -struct android_logger_t { - - /** - * Implements bus_listener_t interface - */ - listener_t listener; - - /** - * Destroy the logger. - */ - void (*destroy)(android_logger_t *this); - -}; - -/** - * Create an Android specific logger instance. - * - * @return logger instance - */ -android_logger_t *android_logger_create(); - -#endif /** ANDROID_LOGGER_H_ @}*/ diff --git a/src/libcharon/plugins/android/android_plugin.c b/src/libcharon/plugins/android/android_plugin.c index 091f34a8e..c0f58e9b4 100644 --- a/src/libcharon/plugins/android/android_plugin.c +++ b/src/libcharon/plugins/android/android_plugin.c @@ -15,7 +15,6 @@ */ #include "android_plugin.h" -#include "android_logger.h" #include "android_handler.h" #include "android_creds.h" #include "android_service.h" @@ -35,11 +34,6 @@ struct private_android_plugin_t { */ android_plugin_t public; - /** - * Android specific logger - */ - android_logger_t *logger; - /** * Android specific DNS handler */ @@ -68,10 +62,8 @@ METHOD(plugin_t, destroy, void, hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler); lib->credmgr->remove_set(lib->credmgr, &this->creds->set); - charon->bus->remove_listener(charon->bus, &this->logger->listener); this->creds->destroy(this->creds); this->handler->destroy(this->handler); - this->logger->destroy(this->logger); DESTROY_IF(this->service); free(this); } @@ -91,14 +83,12 @@ plugin_t *android_plugin_create() .destroy = _destroy, }, }, - .logger = android_logger_create(), .creds = android_creds_create(), ); this->service = android_service_create(this->creds); this->handler = android_handler_create(this->service != NULL); - charon->bus->add_listener(charon->bus, &this->logger->listener); lib->credmgr->add_set(lib->credmgr, &this->creds->set); hydra->attributes->add_handler(hydra->attributes, &this->handler->handler); diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index 487567f2a..81628b80a 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -41,11 +41,6 @@ struct private_android_service_t { */ ike_sa_t *ike_sa; - /** - * job that handles requests from the Android control socket - */ - callback_job_t *job; - /** * android credentials */ @@ -269,17 +264,19 @@ static job_requeue_t initiate(private_android_service_t *this) this->creds->set_username_password(this->creds, user, password); } - ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", IKEV2_UDP_PORT, - hostname, IKEV2_UDP_PORT); + ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", FALSE, + charon->socket->get_port(charon->socket, FALSE), + hostname, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create("android", 2, ike_cfg, CERT_SEND_IF_ASKED, + peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ - host_create_from_string("0.0.0.0", 0) /* virt */, - NULL, FALSE, NULL, NULL); /* pool, mediation */ + TRUE, FALSE, /* mobike, aggressive */ + 0, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); @@ -300,12 +297,17 @@ static job_requeue_t initiate(private_android_service_t *this) 0, "255.255.255.255", 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); peer_cfg->add_child_cfg(peer_cfg, child_cfg); - /* get an additional reference because initiate consumes one */ - child_cfg->get_ref(child_cfg); /* get us an IKE_SA */ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + send_status(this, VPN_ERROR_CONNECTION_FAILED); + return JOB_REQUEUE_NONE; + } + if (!ike_sa->get_peer_cfg(ike_sa)) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); @@ -318,6 +320,8 @@ static job_requeue_t initiate(private_android_service_t *this) /* confirm that we received the request */ send_status(this, i); + /* get an additional reference because initiate consumes one */ + child_cfg->get_ref(child_cfg); if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { DBG1(DBG_CFG, "failed to initiate tunnel"); @@ -376,9 +380,9 @@ android_service_t *android_service_create(android_creds_t *creds) } charon->bus->add_listener(charon->bus, &this->public.listener); - this->job = callback_job_create((callback_job_cb_t)initiate, this, - NULL, NULL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)initiate, this, + NULL, NULL)); return &this->public; } diff --git a/src/libcharon/plugins/android_log/Makefile.am b/src/libcharon/plugins/android_log/Makefile.am new file mode 100644 index 000000000..3c180f1db --- /dev/null +++ b/src/libcharon/plugins/android_log/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-android-log.la +else +plugin_LTLIBRARIES = libstrongswan-android-log.la +endif + +libstrongswan_android_log_la_SOURCES = \ + android_log_plugin.c android_log_plugin.h \ + android_log_logger.c android_log_logger.h + +libstrongswan_android_log_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/android_log/Makefile.in b/src/libcharon/plugins/android_log/Makefile.in new file mode 100644 index 000000000..00f0eb869 --- /dev/null +++ b/src/libcharon/plugins/android_log/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/android_log +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_android_log_la_LIBADD = +am_libstrongswan_android_log_la_OBJECTS = android_log_plugin.lo \ + android_log_logger.lo +libstrongswan_android_log_la_OBJECTS = \ + $(am_libstrongswan_android_log_la_OBJECTS) +libstrongswan_android_log_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_android_log_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_android_log_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_android_log_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_android_log_la_SOURCES) +DIST_SOURCES = $(libstrongswan_android_log_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-android-log.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-android-log.la +libstrongswan_android_log_la_SOURCES = \ + android_log_plugin.c android_log_plugin.h \ + android_log_logger.c android_log_logger.h + +libstrongswan_android_log_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/android_log/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/android_log/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-android-log.la: $(libstrongswan_android_log_la_OBJECTS) $(libstrongswan_android_log_la_DEPENDENCIES) + $(libstrongswan_android_log_la_LINK) $(am_libstrongswan_android_log_la_rpath) $(libstrongswan_android_log_la_OBJECTS) $(libstrongswan_android_log_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_log_logger.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/android_log_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/android_log/android_log_logger.c b/src/libcharon/plugins/android_log/android_log_logger.c new file mode 100644 index 000000000..48bcaa577 --- /dev/null +++ b/src/libcharon/plugins/android_log/android_log_logger.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2010-2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include + +#include "android_log_logger.h" + +#include +#include +#include + +typedef struct private_android_log_logger_t private_android_log_logger_t; + +/** + * Private data of an android_log_logger_t object + */ +struct private_android_log_logger_t { + + /** + * Public interface + */ + android_log_logger_t public; + + /** + * logging level + */ + int level; + + /** + * Mutex to ensure multi-line log messages are not torn apart + */ + mutex_t *mutex; +}; + +METHOD(logger_t, log_, void, + private_android_log_logger_t *this, debug_t group, level_t level, + int thread, ike_sa_t* ike_sa, const char *message) +{ + int prio = level > 1 ? ANDROID_LOG_DEBUG : ANDROID_LOG_INFO; + char sgroup[16]; + const char *current = message, *next; + snprintf(sgroup, sizeof(sgroup), "%N", debug_names, group); + this->mutex->lock(this->mutex); + while (TRUE) + { /* log each line separately */ + next = strchr(current, '\n'); + if (next == NULL) + { + __android_log_print(prio, "charon", "%.2d[%s] %s\n", + thread, sgroup, current); + break; + } + __android_log_print(prio, "charon", "%.2d[%s] %.*s\n", + thread, sgroup, (int)(next - current), current); + current = next + 1; + } + this->mutex->unlock(this->mutex); +} + +METHOD(logger_t, get_level, level_t, + private_android_log_logger_t *this, debug_t group) +{ + return this->level; +} + +METHOD(android_log_logger_t, destroy, void, + private_android_log_logger_t *this) +{ + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * Described in header. + */ +android_log_logger_t *android_log_logger_create() +{ + private_android_log_logger_t *this; + + INIT(this, + .public = { + .logger = { + .log = _log_, + .get_level = _get_level, + }, + .destroy = _destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .level = lib->settings->get_int(lib->settings, + "%s.plugins.android_log.loglevel", 1, charon->name), + ); + + return &this->public; +} + diff --git a/src/libcharon/plugins/android_log/android_log_logger.h b/src/libcharon/plugins/android_log/android_log_logger.h new file mode 100644 index 000000000..ed271bf6c --- /dev/null +++ b/src/libcharon/plugins/android_log/android_log_logger.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup android_log_logger android_log_logger + * @{ @ingroup android_log + */ + +#ifndef ANDROID_LOG_LOGGER_H_ +#define ANDROID_LOG_LOGGER_H_ + +#include + +typedef struct android_log_logger_t android_log_logger_t; + +/** + * Android specific logger. + */ +struct android_log_logger_t { + + /** + * Implements logger_t interface + */ + logger_t logger; + + /** + * Destroy the logger. + */ + void (*destroy)(android_log_logger_t *this); + +}; + +/** + * Create an Android specific logger instance. + * + * @return logger instance + */ +android_log_logger_t *android_log_logger_create(); + +#endif /** ANDROID_LOG_LOGGER_H_ @}*/ diff --git a/src/libcharon/plugins/android_log/android_log_plugin.c b/src/libcharon/plugins/android_log/android_log_plugin.c new file mode 100644 index 000000000..6757c2210 --- /dev/null +++ b/src/libcharon/plugins/android_log/android_log_plugin.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "android_log_plugin.h" +#include "android_log_logger.h" + +#include + +typedef struct private_android_log_plugin_t private_android_log_plugin_t; + +/** + * Private data of an android_log_plugin_t object. + */ +struct private_android_log_plugin_t { + + /** + * Public android_log_plugin_t interface. + */ + android_log_plugin_t public; + + /** + * Android specific logger + */ + android_log_logger_t *logger; + +}; + +METHOD(plugin_t, get_name, char*, + private_android_log_plugin_t *this) +{ + return "android-log"; +} + +METHOD(plugin_t, destroy, void, + private_android_log_plugin_t *this) +{ + charon->bus->remove_logger(charon->bus, &this->logger->logger); + this->logger->destroy(this->logger); + free(this); +} + +/** + * See header + */ +plugin_t *android_log_plugin_create() +{ + private_android_log_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .destroy = _destroy, + }, + }, + .logger = android_log_logger_create(), + ); + + charon->bus->add_logger(charon->bus, &this->logger->logger); + + return &this->public.plugin; +} + diff --git a/src/libcharon/plugins/android_log/android_log_plugin.h b/src/libcharon/plugins/android_log/android_log_plugin.h new file mode 100644 index 000000000..32c4dc10b --- /dev/null +++ b/src/libcharon/plugins/android_log/android_log_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup android_log android_log + * @ingroup cplugins + * + * @defgroup android_log_plugin android_log_plugin + * @{ @ingroup android_log + */ + +#ifndef ANDROID_LOG_PLUGIN_H_ +#define ANDROID_LOG_PLUGIN_H_ + +#include + +typedef struct android_log_plugin_t android_log_plugin_t; + +/** + * Plugin providing an Android specific logger implementation. + */ +struct android_log_plugin_t { + + /** + * Implements plugin interface. + */ + plugin_t plugin; +}; + +#endif /** ANDROID_LOG_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/certexpire/Makefile.in b/src/libcharon/plugins/certexpire/Makefile.in index 929cce20c..4c098fcc7 100644 --- a/src/libcharon/plugins/certexpire/Makefile.in +++ b/src/libcharon/plugins/certexpire/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_certexpire_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_certexpire_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_certexpire_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/certexpire/certexpire_export.c b/src/libcharon/plugins/certexpire/certexpire_export.c index c73b0beda..8e046d0fe 100644 --- a/src/libcharon/plugins/certexpire/certexpire_export.c +++ b/src/libcharon/plugins/certexpire/certexpire_export.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -364,21 +365,28 @@ certexpire_export_t *certexpire_export_create() (hashtable_equals_t)equals, 32), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .local_path = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.local", NULL), + "%s.plugins.certexpire.csv.local", + NULL, charon->name), .remote_path = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.remote", NULL), + "%s.plugins.certexpire.csv.remote", + NULL, charon->name), .separator = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.separator", ","), + "%s.plugins.certexpire.csv.separator", + ",", charon->name), .format = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.format", "%d:%m:%Y"), + "%s.plugins.certexpire.csv.format", + "%d:%m:%Y", charon->name), .fixed_fields = lib->settings->get_bool(lib->settings, - "charon.plugins.certexpire.csv.fixed_fields", TRUE), + "%s.plugins.certexpire.csv.fixed_fields", + TRUE, charon->name), .empty_string = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.empty_string", ""), + "%s.plugins.certexpire.csv.empty_string", + "", charon->name), ); cron = lib->settings->get_str(lib->settings, - "charon.plugins.certexpire.csv.cron", NULL); + "%s.plugins.certexpire.csv.cron", + NULL, charon->name); if (cron) { this->cron = certexpire_cron_create(cron, diff --git a/src/libcharon/plugins/coupling/Makefile.in b/src/libcharon/plugins/coupling/Makefile.in index df4420b04..9ad158b4c 100644 --- a/src/libcharon/plugins/coupling/Makefile.in +++ b/src/libcharon/plugins/coupling/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_coupling_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_coupling_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_coupling_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/coupling/coupling_validator.c b/src/libcharon/plugins/coupling/coupling_validator.c index 06b6f7d86..539be7548 100644 --- a/src/libcharon/plugins/coupling/coupling_validator.c +++ b/src/libcharon/plugins/coupling/coupling_validator.c @@ -70,7 +70,11 @@ static bool get_cert_hash(private_coupling_validator_t *this, { return FALSE; } - this->hasher->get_hash(this->hasher, encoding, buf); + if (!this->hasher->get_hash(this->hasher, encoding, buf)) + { + free(encoding.ptr); + return FALSE; + } free(encoding.ptr); chunk_to_hex(chunk_create(buf, this->hasher->get_hash_size(this->hasher)), hex, FALSE); @@ -195,17 +199,6 @@ coupling_validator_t *coupling_validator_create() { private_coupling_validator_t *this; char *path, *hash; - int i; - struct { - hash_algorithm_t alg; - char *name; - } hash_types[] = { - { HASH_MD5, "md5"}, - { HASH_SHA1, "sha1"}, - { HASH_SHA256, "sha256"}, - { HASH_SHA384, "sha384"}, - { HASH_SHA512, "sha512"}, - }; INIT(this, .public = { @@ -216,20 +209,15 @@ coupling_validator_t *coupling_validator_create() }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .max_couplings = lib->settings->get_int(lib->settings, - "charon.plugins.coupling.max", 1), + "%s.plugins.coupling.max", 1, + charon->name), ); hash = lib->settings->get_str(lib->settings, - "charon.plugins.coupling.hash", "sha1"); - for (i = 0; i < countof(hash_types); i++) - { - if (strcaseeq(hash_types[i].name, hash)) - { - this->hasher = lib->crypto->create_hasher(lib->crypto, - hash_types[i].alg); - break; - } - } + "%s.plugins.coupling.hash", "sha1", + charon->name); + this->hasher = lib->crypto->create_hasher(lib->crypto, + enum_from_name(hash_algorithm_short_names, hash)); if (!this->hasher) { DBG1(DBG_CFG, "unsupported coupling hash algorithm: %s", hash); @@ -238,7 +226,8 @@ coupling_validator_t *coupling_validator_create() } path = lib->settings->get_str(lib->settings, - "charon.plugins.coupling.file", NULL); + "%s.plugins.coupling.file", NULL, + charon->name); if (!path) { DBG1(DBG_CFG, "coupling file path unspecified"); diff --git a/src/libcharon/plugins/dhcp/Makefile.in b/src/libcharon/plugins/dhcp/Makefile.in index 089afd39d..ec42d8de6 100644 --- a/src/libcharon/plugins/dhcp/Makefile.in +++ b/src/libcharon/plugins/dhcp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_dhcp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_dhcp_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_dhcp_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_dhcp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/dhcp/dhcp_provider.c b/src/libcharon/plugins/dhcp/dhcp_provider.c index a6a887780..8bc547462 100644 --- a/src/libcharon/plugins/dhcp/dhcp_provider.c +++ b/src/libcharon/plugins/dhcp/dhcp_provider.c @@ -81,18 +81,29 @@ static uintptr_t hash_transaction(dhcp_transaction_t *transaction) } METHOD(attribute_provider_t, acquire_address, host_t*, - private_dhcp_provider_t *this, char *pool, + private_dhcp_provider_t *this, linked_list_t *pools, identification_t *id, host_t *requested) { - if (streq(pool, "dhcp")) - { - dhcp_transaction_t *transaction, *old; - host_t *vip; + dhcp_transaction_t *transaction, *old; + enumerator_t *enumerator; + char *pool; + host_t *vip = NULL; + if (requested->get_family(requested) != AF_INET) + { + return NULL; + } + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &pool)) + { + if (!streq(pool, "dhcp")) + { + continue; + } transaction = this->socket->enroll(this->socket, id); if (!transaction) { - return NULL; + continue; } vip = transaction->get_address(transaction); vip = vip->clone(vip); @@ -101,19 +112,32 @@ METHOD(attribute_provider_t, acquire_address, host_t*, (void*)hash_transaction(transaction), transaction); this->mutex->unlock(this->mutex); DESTROY_IF(old); - return vip; + break; } - return NULL; + enumerator->destroy(enumerator); + return vip; } METHOD(attribute_provider_t, release_address, bool, - private_dhcp_provider_t *this, char *pool, + private_dhcp_provider_t *this, linked_list_t *pools, host_t *address, identification_t *id) { - if (streq(pool, "dhcp")) - { - dhcp_transaction_t *transaction; + dhcp_transaction_t *transaction; + enumerator_t *enumerator; + bool found = FALSE; + char *pool; + if (address->get_family(address) != AF_INET) + { + return FALSE; + } + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &pool)) + { + if (!streq(pool, "dhcp")) + { + continue; + } this->mutex->lock(this->mutex); transaction = this->transactions->remove(this->transactions, (void*)hash_id_host(id, address)); @@ -122,25 +146,34 @@ METHOD(attribute_provider_t, release_address, bool, { this->socket->release(this->socket, transaction); transaction->destroy(transaction); - return TRUE; + found = TRUE; + break; } } - return FALSE; + enumerator->destroy(enumerator); + return found; } METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, - private_dhcp_provider_t *this, char *pool, identification_t *id, - host_t *vip) + private_dhcp_provider_t *this, linked_list_t *pools, identification_t *id, + linked_list_t *vips) { - dhcp_transaction_t *transaction; + dhcp_transaction_t *transaction = NULL; + enumerator_t *enumerator; + host_t *vip; - if (!vip) + this->mutex->lock(this->mutex); + enumerator = vips->create_enumerator(vips); + while (enumerator->enumerate(enumerator, &vip)) { - return NULL; + transaction = this->transactions->get(this->transactions, + (void*)hash_id_host(id, vip)); + if (transaction) + { + break; + } } - this->mutex->lock(this->mutex); - transaction = this->transactions->get(this->transactions, - (void*)hash_id_host(id, vip)); + enumerator->destroy(enumerator); if (!transaction) { this->mutex->unlock(this->mutex); diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c index 5d98e5b8d..f469c5a35 100644 --- a/src/libcharon/plugins/dhcp/dhcp_socket.c +++ b/src/libcharon/plugins/dhcp/dhcp_socket.c @@ -107,9 +107,9 @@ struct private_dhcp_socket_t { host_t *dst; /** - * Callback job receiving DHCP responses + * Force configured destination address */ - callback_job_t *job; + bool force_dst; }; /** @@ -271,7 +271,7 @@ static bool send_dhcp(private_dhcp_socket_t *this, ssize_t len; dst = transaction->get_server(transaction); - if (!dst) + if (!dst || this->force_dst) { dst = this->dst; } @@ -371,7 +371,11 @@ METHOD(dhcp_socket_t, enroll, dhcp_transaction_t*, u_int32_t id; int try; - this->rng->get_bytes(this->rng, sizeof(id), (u_int8_t*)&id); + if (!this->rng->get_bytes(this->rng, sizeof(id), (u_int8_t*)&id)) + { + DBG1(DBG_CFG, "DHCP DISCOVER failed, no transaction ID"); + return NULL; + } transaction = dhcp_transaction_create(id, identity); this->mutex->lock(this->mutex); @@ -613,10 +617,6 @@ static job_requeue_t receive_dhcp(private_dhcp_socket_t *this) METHOD(dhcp_socket_t, destroy, void, private_dhcp_socket_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } while (this->waiting) { this->condvar->signal(this->condvar); @@ -648,7 +648,13 @@ METHOD(dhcp_socket_t, destroy, void, dhcp_socket_t *dhcp_socket_create() { private_dhcp_socket_t *this; - struct sockaddr_in src; + struct sockaddr_in src = { + .sin_family = AF_INET, + .sin_port = htons(DHCP_CLIENT_PORT), + .sin_addr = { + .s_addr = INADDR_ANY, + }, + }; int on = 1; struct sock_filter dhcp_filter_code[] = { BPF_STMT(BPF_LD+BPF_B+BPF_ABS, @@ -704,10 +710,14 @@ dhcp_socket_t *dhcp_socket_create() return NULL; } this->identity_lease = lib->settings->get_bool(lib->settings, - "charon.plugins.dhcp.identity_lease", FALSE); + "%s.plugins.dhcp.identity_lease", FALSE, + charon->name); + this->force_dst = lib->settings->get_str(lib->settings, + "%s.plugins.dhcp.force_server_address", FALSE, + charon->name); this->dst = host_create_from_string(lib->settings->get_str(lib->settings, - "charon.plugins.dhcp.server", "255.255.255.255"), - DHCP_SERVER_PORT); + "%s.plugins.dhcp.server", "255.255.255.255", + charon->name), DHCP_SERVER_PORT); if (!this->dst) { DBG1(DBG_CFG, "configured DHCP server address invalid"); @@ -734,9 +744,6 @@ dhcp_socket_t *dhcp_socket_create() destroy(this); return NULL; } - src.sin_family = AF_INET; - src.sin_port = htons(DHCP_CLIENT_PORT); - src.sin_addr.s_addr = INADDR_ANY; if (bind(this->send, (struct sockaddr*)&src, sizeof(src)) == -1) { DBG1(DBG_CFG, "unable to bind DHCP send socket: %s", strerror(errno)); @@ -760,9 +767,9 @@ dhcp_socket_t *dhcp_socket_create() return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_dhcp, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive_dhcp, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/duplicheck/Makefile.in b/src/libcharon/plugins/duplicheck/Makefile.in index 87984a182..d739660da 100644 --- a/src/libcharon/plugins/duplicheck/Makefile.in +++ b/src/libcharon/plugins/duplicheck/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -92,7 +93,7 @@ PROGRAMS = $(ipsec_PROGRAMS) am_duplicheck_OBJECTS = duplicheck.$(OBJEXT) duplicheck_OBJECTS = $(am_duplicheck_OBJECTS) duplicheck_LDADD = $(LDADD) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -119,6 +120,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -213,11 +215,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -234,11 +239,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -254,6 +260,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -263,7 +270,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.c b/src/libcharon/plugins/duplicheck/duplicheck_listener.c index 226b2bd4e..4f59e034f 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_listener.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_listener.c @@ -176,9 +176,9 @@ METHOD(listener_t, ike_updown, bool, METHOD(listener_t, message_hook, bool, private_duplicheck_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { - if (incoming && !message->get_request(message)) + if (incoming && plain && !message->get_request(message)) { identification_t *id; entry_t *entry; diff --git a/src/libcharon/plugins/duplicheck/duplicheck_notify.c b/src/libcharon/plugins/duplicheck/duplicheck_notify.c index b86f1ef3d..06a88ed7d 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_notify.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_notify.c @@ -42,11 +42,6 @@ struct private_duplicheck_notify_t { */ duplicheck_notify_t public; - /** - * Callback job dispatching connections - */ - callback_job_t *job; - /** * Mutex to lock list */ @@ -89,7 +84,8 @@ static bool open_socket(private_duplicheck_notify_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->uid, charon->gid) != 0) + if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing duplicheck socket permissions failed: %s", strerror(errno)); @@ -167,10 +163,6 @@ METHOD(duplicheck_notify_t, destroy, void, enumerator_t *enumerator; uintptr_t fd; - if (this->job) - { - this->job->cancel(this->job); - } enumerator = this->connected->create_enumerator(this->connected); while (enumerator->enumerate(enumerator, &fd)) { @@ -203,9 +195,9 @@ duplicheck_notify_t *duplicheck_notify_create() destroy(this); return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c index df28e7f12..100ef0c2d 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c @@ -66,7 +66,7 @@ plugin_t *duplicheck_plugin_create() private_duplicheck_plugin_t *this; if (!lib->settings->get_bool(lib->settings, - "charon.plugins.duplicheck.enable", TRUE)) + "%s.plugins.duplicheck.enable", TRUE, charon->name)) { return NULL; } diff --git a/src/libcharon/plugins/eap_aka/Makefile.in b/src/libcharon/plugins/eap_aka/Makefile.in index e7a3d780a..e098c2c75 100644 --- a/src/libcharon/plugins/eap_aka/Makefile.in +++ b/src/libcharon/plugins/eap_aka/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_eap_aka_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_aka_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_aka_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_aka/eap_aka_peer.c b/src/libcharon/plugins/eap_aka/eap_aka_peer.c index 8c392405e..810a19c55 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_peer.c +++ b/src/libcharon/plugins/eap_aka/eap_aka_peer.c @@ -80,13 +80,31 @@ struct private_eap_aka_peer_t { u_int16_t counter; }; +/** + * Generate a payload from a message, destroy message + */ +static bool generate_payload(simaka_message_t *message, chunk_t data, + eap_payload_t **out) +{ + chunk_t chunk; + bool ok; + + ok = message->generate(message, data, &chunk); + if (ok) + { + *out = eap_payload_create_data_own(chunk); + } + message->destroy(message); + return ok; +} + /** * Create a AKA_CLIENT_ERROR: "Unable to process" */ -static eap_payload_t* create_client_error(private_eap_aka_peer_t *this) +static bool create_client_error(private_eap_aka_peer_t *this, + eap_payload_t **out) { simaka_message_t *message; - eap_payload_t *out; u_int16_t encoded; DBG1(DBG_IKE, "sending client error '%N'", @@ -97,9 +115,8 @@ static eap_payload_t* create_client_error(private_eap_aka_peer_t *this) encoded = htons(AKA_UNABLE_TO_PROCESS); message->add_attribute(message, AT_CLIENT_ERROR_CODE, chunk_create((char*)&encoded, sizeof(encoded))); - out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - return out; + + return generate_payload(message, chunk_empty, out); } /** @@ -134,8 +151,11 @@ static status_t process_identity(private_eap_aka_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this); enumerator->destroy(enumerator); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -175,9 +195,10 @@ static status_t process_identity(private_eap_aka_peer_t *this, { message->add_attribute(message, AT_IDENTITY, id); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } return NEED_MORE; } @@ -210,8 +231,11 @@ static status_t process_challenge(private_eap_aka_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this); enumerator->destroy(enumerator); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -222,7 +246,10 @@ static status_t process_challenge(private_eap_aka_peer_t *this, if (!rand.len || !autn.len) { DBG1(DBG_IKE, "received invalid EAP-AKA challenge message"); - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } @@ -237,9 +264,10 @@ static status_t process_challenge(private_eap_aka_peer_t *this, AKA_SYNCHRONIZATION_FAILURE, this->crypto); message->add_attribute(message, AT_AUTS, chunk_create(auts, AKA_AUTS_LEN)); - *out = eap_payload_create_data_own(message->generate(message, - chunk_empty)); - message->destroy(message); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } return NEED_MORE; } if (status != SUCCESS) @@ -248,9 +276,10 @@ static status_t process_challenge(private_eap_aka_peer_t *this, this->permanent, simaka_subtype_names, AKA_AUTHENTICATION_REJECT); message = simaka_message_create(FALSE, in->get_identifier(in), EAP_AKA, AKA_AUTHENTICATION_REJECT, this->crypto); - *out = eap_payload_create_data_own(message->generate(message, - chunk_empty)); - message->destroy(message); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } return NEED_MORE; } @@ -261,16 +290,22 @@ static status_t process_challenge(private_eap_aka_peer_t *this, } data = chunk_cata("cc", chunk_create(ik, AKA_IK_LEN), chunk_create(ck, AKA_CK_LEN)); - free(this->msk.ptr); - this->msk = this->crypto->derive_keys_full(this->crypto, id, data, &mk); + chunk_clear(&this->msk); + if (!this->crypto->derive_keys_full(this->crypto, id, data, &mk, &this->msk)) + { + return FAILED; + } memcpy(this->mk, mk.ptr, mk.len); - free(mk.ptr); + chunk_clear(&mk); /* Verify AT_MAC attribute and parse() again after key derivation, * reading encrypted attributes */ if (!in->verify(in, chunk_empty) || !in->parse(in)) { - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } @@ -300,8 +335,10 @@ static status_t process_challenge(private_eap_aka_peer_t *this, message = simaka_message_create(FALSE, this->identifier, EAP_AKA, AKA_CHALLENGE, this->crypto); message->add_attribute(message, AT_RES, chunk_create(res, res_len)); - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } return NEED_MORE; } @@ -332,17 +369,26 @@ static status_t process_reauthentication(private_eap_aka_peer_t *this, { DBG1(DBG_IKE, "received %N, but not expected", simaka_subtype_names, AKA_REAUTHENTICATION); - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } - this->crypto->derive_keys_reauth(this->crypto, - chunk_create(this->mk, HASH_SIZE_SHA1)); + if (!this->crypto->derive_keys_reauth(this->crypto, + chunk_create(this->mk, HASH_SIZE_SHA1))) + { + return FAILED; + } /* verify MAC and parse again with decryption key */ if (!in->verify(in, chunk_empty) || !in->parse(in)) { - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } @@ -363,8 +409,11 @@ static status_t process_reauthentication(private_eap_aka_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this); enumerator->destroy(enumerator); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -375,7 +424,10 @@ static status_t process_reauthentication(private_eap_aka_peer_t *this, if (!nonce.len || !counter.len) { DBG1(DBG_IKE, "EAP-AKA/Request/Reauthentication message incomplete"); - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } @@ -388,10 +440,14 @@ static status_t process_reauthentication(private_eap_aka_peer_t *this, } else { - free(this->msk.ptr); - this->msk = this->crypto->derive_keys_reauth_msk(this->crypto, - this->reauth, counter, nonce, - chunk_create(this->mk, HASH_SIZE_SHA1)); + chunk_clear(&this->msk); + if (!this->crypto->derive_keys_reauth_msk(this->crypto, + this->reauth, counter, nonce, + chunk_create(this->mk, HASH_SIZE_SHA1), &this->msk)) + { + message->destroy(message); + return FAILED; + } if (id.len) { identification_t *reauth; @@ -403,8 +459,10 @@ static status_t process_reauthentication(private_eap_aka_peer_t *this, } } message->add_attribute(message, AT_COUNTER, counter); - *out = eap_payload_create_data_own(message->generate(message, nonce)); - message->destroy(message); + if (!generate_payload(message, nonce, out)) + { + return FAILED; + } return NEED_MORE; } @@ -454,13 +512,17 @@ static status_t process_notification(private_eap_aka_peer_t *this, { /* empty notification reply */ message = simaka_message_create(FALSE, this->identifier, EAP_AKA, AKA_NOTIFICATION, this->crypto); - *out = eap_payload_create_data_own(message->generate(message, - chunk_empty)); - message->destroy(message); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } } else { - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } } return NEED_MORE; } @@ -478,13 +540,19 @@ METHOD(eap_method_t, process, status_t, message = simaka_message_create_from_payload(in->get_data(in), this->crypto); if (!message) { - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } if (!message->parse(message)) { message->destroy(message); - *out = create_client_error(this); + if (!create_client_error(this, out)) + { + return FAILED; + } return NEED_MORE; } switch (message->get_subtype(message)) @@ -504,8 +572,14 @@ METHOD(eap_method_t, process, status_t, default: DBG1(DBG_IKE, "unable to process EAP-AKA subtype %N", simaka_subtype_names, message->get_subtype(message)); - *out = create_client_error(this); - status = NEED_MORE; + if (!create_client_error(this, out)) + { + status = FAILED; + } + else + { + status = NEED_MORE; + } break; } message->destroy(message); diff --git a/src/libcharon/plugins/eap_aka/eap_aka_peer.h b/src/libcharon/plugins/eap_aka/eap_aka_peer.h index 974ba2721..b6ab5cdc5 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_peer.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_peer.h @@ -23,7 +23,7 @@ typedef struct eap_aka_peer_t eap_aka_peer_t; -#include +#include /** * EAP-AKA peer implementation. diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.c b/src/libcharon/plugins/eap_aka/eap_aka_server.c index d8e85ceef..b7608382d 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_server.c +++ b/src/libcharon/plugins/eap_aka/eap_aka_server.c @@ -118,6 +118,24 @@ struct private_eap_aka_server_t { bool synchronized; }; +/** + * Generate a payload from a message, destroy message + */ +static bool generate_payload(simaka_message_t *message, chunk_t data, + eap_payload_t **out) +{ + chunk_t chunk; + bool ok; + + ok = message->generate(message, data, &chunk); + if (ok) + { + *out = eap_payload_create_data_own(chunk); + } + message->destroy(message); + return ok; +} + /** * Create EAP-AKA/Request/Identity message */ @@ -139,9 +157,10 @@ static status_t identity(private_eap_aka_server_t *this, eap_payload_t **out) { message->add_attribute(message, AT_PERMANENT_ID_REQ, chunk_empty); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } this->pending = AKA_IDENTITY; return NEED_MORE; } @@ -180,8 +199,11 @@ static status_t challenge(private_eap_aka_server_t *this, eap_payload_t **out) } data = chunk_cata("cc", chunk_create(ik, AKA_IK_LEN), chunk_create(ck, AKA_CK_LEN)); - free(this->msk.ptr); - this->msk = this->crypto->derive_keys_full(this->crypto, id, data, &mk); + chunk_clear(&this->msk); + if (!this->crypto->derive_keys_full(this->crypto, id, data, &mk, &this->msk)) + { + return FAILED; + } this->rand = chunk_clone(chunk_create(rand, AKA_RAND_LEN)); this->xres = chunk_clone(chunk_create(xres, xres_len)); @@ -190,6 +212,7 @@ static status_t challenge(private_eap_aka_server_t *this, eap_payload_t **out) message->add_attribute(message, AT_RAND, this->rand); message->add_attribute(message, AT_AUTN, chunk_create(autn, AKA_AUTN_LEN)); id = this->mgr->provider_gen_reauth(this->mgr, this->permanent, mk.ptr); + free(mk.ptr); if (id) { message->add_attribute(message, AT_NEXT_REAUTH_ID, @@ -203,10 +226,10 @@ static status_t challenge(private_eap_aka_server_t *this, eap_payload_t **out) id->get_encoding(id)); id->destroy(id); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - - free(mk.ptr); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } this->pending = AKA_CHALLENGE; return NEED_MORE; } @@ -226,15 +249,21 @@ static status_t reauthenticate(private_eap_aka_server_t *this, DBG1(DBG_IKE, "initiating EAP-AKA reauthentication"); rng = this->crypto->get_rng(this->crypto); - rng->allocate_bytes(rng, NONCE_LEN, &this->nonce); + if (!rng->allocate_bytes(rng, NONCE_LEN, &this->nonce)) + { + return FAILED; + } mkc = chunk_create(mk, HASH_SIZE_SHA1); counter = htons(counter); this->counter = chunk_clone(chunk_create((char*)&counter, sizeof(counter))); - this->crypto->derive_keys_reauth(this->crypto, mkc); - this->msk = this->crypto->derive_keys_reauth_msk(this->crypto, - this->reauth, this->counter, this->nonce, mkc); + if (!this->crypto->derive_keys_reauth(this->crypto, mkc) || + !this->crypto->derive_keys_reauth_msk(this->crypto, + this->reauth, this->counter, this->nonce, mkc, &this->msk)) + { + return FAILED; + } message = simaka_message_create(TRUE, this->identifier++, EAP_AKA, AKA_REAUTHENTICATION, this->crypto); @@ -247,9 +276,10 @@ static status_t reauthenticate(private_eap_aka_server_t *this, next->get_encoding(next)); next->destroy(next); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } this->pending = SIM_REAUTHENTICATION; return NEED_MORE; } @@ -691,7 +721,7 @@ eap_aka_server_t *eap_aka_server_create(identification_t *server, this->permanent = peer->clone(peer); this->use_reauth = this->use_pseudonym = this->use_permanent = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-aka.request_identity", TRUE); + "%s.plugins.eap-aka.request_identity", TRUE, charon->name); /* generate a non-zero identifier */ do { diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.h b/src/libcharon/plugins/eap_aka/eap_aka_server.h index 5ab1c4dfd..5c95180ac 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_server.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_server.h @@ -23,7 +23,7 @@ typedef struct eap_aka_server_t eap_aka_server_t; -#include +#include /** * EAP-AKA server implementation. diff --git a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in index b0890fb39..4655d341b 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in +++ b/src/libcharon/plugins/eap_aka_3gpp2/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_eap_aka_3gpp2_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_aka_3gpp2_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_aka_3gpp2_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c index cec06fbd7..1bfc39e5a 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_card.c @@ -74,13 +74,19 @@ METHOD(simaka_card_t, get_quintuplet, status_t, mac = autn + AKA_SQN_LEN + AKA_AMF_LEN; /* XOR anonymity key AK into SQN to decrypt it */ - this->f->f5(this->f, k, rand, ak); + if (!this->f->f5(this->f, k, rand, ak)) + { + return FAILED; + } DBG3(DBG_IKE, "using ak %b", ak, AKA_AK_LEN); memxor(sqn, ak, AKA_SQN_LEN); DBG3(DBG_IKE, "using sqn %b", sqn, AKA_SQN_LEN); /* calculate expected MAC and compare against received one */ - this->f->f1(this->f, k, rand, sqn, amf, xmac); + if (!this->f->f1(this->f, k, rand, sqn, amf, xmac)) + { + return FAILED; + } if (!memeq(mac, xmac, AKA_MAC_LEN)) { DBG1(DBG_IKE, "received MAC does not match XMAC"); @@ -98,11 +104,13 @@ METHOD(simaka_card_t, get_quintuplet, status_t, /* update stored SQN to the received one */ memcpy(this->sqn, sqn, AKA_SQN_LEN); - /* CK/IK */ - this->f->f3(this->f, k, rand, ck); - this->f->f4(this->f, k, rand, ik); - /* calculate RES */ - this->f->f2(this->f, k, rand, res); + /* CK/IK, calculate RES */ + if (!this->f->f3(this->f, k, rand, ck) || + !this->f->f4(this->f, k, rand, ik) || + !this->f->f2(this->f, k, rand, res)) + { + return FAILED; + } *res_len = AKA_RES_MAX; return SUCCESS; @@ -122,8 +130,11 @@ METHOD(simaka_card_t, resync, bool, /* AMF is set to zero in resync */ memset(amf, 0, AKA_AMF_LEN); - this->f->f5star(this->f, k, rand, aks); - this->f->f1star(this->f, k, rand, this->sqn, amf, macs); + if (!this->f->f5star(this->f, k, rand, aks) || + !this->f->f1star(this->f, k, rand, this->sqn, amf, macs)) + { + return FALSE; + } /* AUTS = SQN xor AKS | MACS */ memcpy(auts, this->sqn, AKA_SQN_LEN); memxor(auts, aks, AKA_AK_LEN); @@ -160,12 +171,13 @@ eap_aka_3gpp2_card_t *eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t *f) }, .f = f, .seq_check = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-aka-3gpp2.seq_check", + "%s.plugins.eap-aka-3gpp2.seq_check", #ifdef SEQ_CHECK /* handle legacy compile time configuration as default */ - TRUE), + TRUE, #else /* !SEQ_CHECK */ - FALSE), + FALSE, #endif /* SEQ_CHECK */ + charon->name), ); eap_aka_3gpp2_get_sqn(this->sqn, 0); diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c index d000bebbb..93ea8d08c 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.c @@ -170,12 +170,12 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b) * Step 3 of the various fx() functions: * XOR the key into the SHA1 IV */ -static void step3(prf_t *prf, u_char k[AKA_K_LEN], +static bool step3(prf_t *prf, u_char k[AKA_K_LEN], u_char payload[AKA_PAYLOAD_LEN], u_int8_t h[HASH_SIZE_SHA1]) { /* use the keyed hasher to build the hash */ - prf->set_key(prf, chunk_create(k, AKA_K_LEN)); - prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h); + return prf->set_key(prf, chunk_create(k, AKA_K_LEN)) && + prf->get_bytes(prf, chunk_create(payload, AKA_PAYLOAD_LEN), h); } /** @@ -211,7 +211,7 @@ static void step4(u_char x[HASH_SIZE_SHA1]) /** * Calculation function for f2(), f3(), f4() */ -static void fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN], +static bool fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char out[AKA_MAC_LEN]) { u_char payload[AKA_PAYLOAD_LEN]; @@ -230,16 +230,20 @@ static void fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN], payload[35] ^= i; payload[51] ^= i; - step3(prf, k, payload, h); + if (!step3(prf, k, payload, h)) + { + return FALSE; + } step4(h); memcpy(out + i * 8, h, 8); } + return TRUE; } /** * Calculation function of f1() and f1star() */ -static void f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN], +static bool f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]) { @@ -257,15 +261,19 @@ static void f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN], memxor(payload + 34, sqn, AKA_SQN_LEN); memxor(payload + 42, amf, AKA_AMF_LEN); - step3(prf, k, payload, h); + if (!step3(prf, k, payload, h)) + { + return FALSE; + } step4(h); memcpy(mac, h, AKA_MAC_LEN); + return TRUE; } /** * Calculation function of f5() and f5star() */ -static void f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN], +static bool f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]) { u_char payload[AKA_PAYLOAD_LEN]; @@ -276,88 +284,120 @@ static void f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN], memxor(payload + 12, fmk.ptr, fmk.len); memxor(payload + 16, rand, AKA_RAND_LEN); - step3(prf, k, payload, h); + if (!step3(prf, k, payload, h)) + { + return FALSE; + } step4(h); memcpy(ak, h, AKA_AK_LEN); + return TRUE; } /** * Calculate MAC from RAND, SQN, AMF using K */ -METHOD(eap_aka_3gpp2_functions_t, f1, void, +METHOD(eap_aka_3gpp2_functions_t, f1, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]) { - f1x(this->prf, F1, k, rand, sqn, amf, mac); - DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN); + if (f1x(this->prf, F1, k, rand, sqn, amf, mac)) + { + DBG3(DBG_IKE, "MAC %b", mac, AKA_MAC_LEN); + return TRUE; + } + return FALSE; } /** * Calculate MACS from RAND, SQN, AMF using K */ -METHOD(eap_aka_3gpp2_functions_t, f1star, void, +METHOD(eap_aka_3gpp2_functions_t, f1star, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]) { - f1x(this->prf, F1STAR, k, rand, sqn, amf, macs); - DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN); + if (f1x(this->prf, F1STAR, k, rand, sqn, amf, macs)) + { + DBG3(DBG_IKE, "MACS %b", macs, AKA_MAC_LEN); + return TRUE; + } + return FALSE; } /** * Calculate RES from RAND using K */ -METHOD(eap_aka_3gpp2_functions_t, f2, void, +METHOD(eap_aka_3gpp2_functions_t, f2, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX]) { - fx(this->prf, F2, k, rand, res); - DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX); + if (fx(this->prf, F2, k, rand, res)) + { + DBG3(DBG_IKE, "RES %b", res, AKA_RES_MAX); + return TRUE; + } + return FALSE; } /** * Calculate CK from RAND using K */ -METHOD(eap_aka_3gpp2_functions_t, f3, void, +METHOD(eap_aka_3gpp2_functions_t, f3, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]) { - fx(this->prf, F3, k, rand, ck); - DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN); + if (fx(this->prf, F3, k, rand, ck)) + { + DBG3(DBG_IKE, "CK %b", ck, AKA_CK_LEN); + return TRUE; + } + return FALSE; } /** * Calculate IK from RAND using K */ -METHOD(eap_aka_3gpp2_functions_t, f4, void, +METHOD(eap_aka_3gpp2_functions_t, f4, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]) { - fx(this->prf, F4, k, rand, ik); - DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN); + if (fx(this->prf, F4, k, rand, ik)) + { + DBG3(DBG_IKE, "IK %b", ik, AKA_IK_LEN); + return TRUE; + } + return FALSE; } /** * Calculate AK from a RAND using K */ -METHOD(eap_aka_3gpp2_functions_t, f5, void, +METHOD(eap_aka_3gpp2_functions_t, f5, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]) { - f5x(this->prf, F5, k, rand, ak); - DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN); + if (f5x(this->prf, F5, k, rand, ak)) + { + DBG3(DBG_IKE, "AK %b", ak, AKA_AK_LEN); + return TRUE; + } + return FALSE; } /** * Calculate AKS from a RAND using K */ -METHOD(eap_aka_3gpp2_functions_t, f5star, void, +METHOD(eap_aka_3gpp2_functions_t, f5star, bool, private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]) { - f5x(this->prf, F5STAR, k, rand, aks); - DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN); + if (f5x(this->prf, F5STAR, k, rand, aks)) + { + DBG3(DBG_IKE, "AKS %b", aks, AKA_AK_LEN); + return TRUE; + } + return FALSE; } METHOD(eap_aka_3gpp2_functions_t, destroy, void, diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h index 855efec3e..2706da349 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_functions.h @@ -45,8 +45,9 @@ struct eap_aka_3gpp2_functions_t { * @param sqn sequence number * @param amf authentication management field * @param mac buffer receiving mac MAC + * @return TRUE if calculations successful */ - void (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]); @@ -58,8 +59,9 @@ struct eap_aka_3gpp2_functions_t { * @param sqn sequence number * @param amf authentication management field * @param macs buffer receiving resynchronization mac MACS + * @return TRUE if calculations successful */ - void (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]); @@ -69,8 +71,9 @@ struct eap_aka_3gpp2_functions_t { * @param k secret key K * @param rand random value RAND * @param res buffer receiving result RES, uses full 128 bit + * @return TRUE if calculations successful */ - void (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_MAX]); /** * Calculate CK from RAND using K @@ -78,8 +81,9 @@ struct eap_aka_3gpp2_functions_t { * @param k secret key K * @param rand random value RAND * @param macs buffer receiving encryption key CK + * @return TRUE if calculations successful */ - void (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]); /** * Calculate IK from RAND using K @@ -87,8 +91,9 @@ struct eap_aka_3gpp2_functions_t { * @param k secret key K * @param rand random value RAND * @param macs buffer receiving integrity key IK + * @return TRUE if calculations successful */ - void (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]); /** * Calculate AK from a RAND using K @@ -96,8 +101,9 @@ struct eap_aka_3gpp2_functions_t { * @param k secret key K * @param rand random value RAND * @param macs buffer receiving anonymity key AK + * @return TRUE if calculations successful */ - void (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]); /** * Calculate AKS from a RAND using K @@ -105,8 +111,9 @@ struct eap_aka_3gpp2_functions_t { * @param k secret key K * @param rand random value RAND * @param macs buffer receiving resynchronization anonymity key AKS + * @return TRUE if calculations successful */ - void (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], + bool (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]); /** diff --git a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c index b2b43da2a..0be122158 100644 --- a/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c +++ b/src/libcharon/plugins/eap_aka_3gpp2/eap_aka_3gpp2_provider.c @@ -90,12 +90,12 @@ METHOD(simaka_provider_t, get_quintuplet, bool, /* generate RAND: we use a registered RNG, not f0() proposed in S.S0055 */ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->get_bytes(rng, AKA_RAND_LEN, rand)) { DBG1(DBG_IKE, "generating RAND for AKA failed"); + DESTROY_IF(rng); return FALSE; } - rng->get_bytes(rng, AKA_RAND_LEN, rand); rng->destroy(rng); if (!eap_aka_3gpp2_get_k(id, k)) @@ -107,12 +107,13 @@ METHOD(simaka_provider_t, get_quintuplet, bool, DBG3(DBG_IKE, "generated rand %b", rand, AKA_RAND_LEN); DBG3(DBG_IKE, "using K %b", k, AKA_K_LEN); - /* MAC */ - this->f->f1(this->f, k, rand, this->sqn, amf, mac); - /* AK */ - this->f->f5(this->f, k, rand, ak); - /* XRES as expected from client */ - this->f->f2(this->f, k, rand, xres); + /* MAC, AK, XRES as expected from client */ + if (!this->f->f1(this->f, k, rand, this->sqn, amf, mac) || + !this->f->f5(this->f, k, rand, ak) || + !this->f->f2(this->f, k, rand, xres)) + { + return FALSE; + } *xres_len = AKA_RES_MAX; /* AUTN = (SQN xor AK) || AMF || MAC */ memcpy(autn, this->sqn, AKA_SQN_LEN); @@ -121,9 +122,11 @@ METHOD(simaka_provider_t, get_quintuplet, bool, memcpy(autn + AKA_SQN_LEN + AKA_AMF_LEN, mac, AKA_MAC_LEN); DBG3(DBG_IKE, "AUTN %b", autn, AKA_AUTN_LEN); /* CK/IK */ - this->f->f3(this->f, k, rand, ck); - this->f->f4(this->f, k, rand, ik); - + if (!this->f->f3(this->f, k, rand, ck) || + !this->f->f4(this->f, k, rand, ik)) + { + return FALSE; + } return TRUE; } @@ -143,12 +146,18 @@ METHOD(simaka_provider_t, resync, bool, /* AUTHS = (AK xor SQN) | MAC */ sqn = auts; macs = auts + AKA_SQN_LEN; - this->f->f5star(this->f, k, rand, aks); + if (!this->f->f5star(this->f, k, rand, aks)) + { + return FALSE; + } memxor(sqn, aks, AKA_AK_LEN); /* verify XMACS, AMF of zero is used in resynchronization */ memset(amf, 0, AKA_AMF_LEN); - this->f->f1star(this->f, k, rand, sqn, amf, xmacs); + if (!this->f->f1star(this->f, k, rand, sqn, amf, xmacs)) + { + return FALSE; + } if (!memeq(macs, xmacs, AKA_MAC_LEN)) { DBG1(DBG_IKE, "received MACS does not match XMACS"); diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.am b/src/libcharon/plugins/eap_dynamic/Makefile.am new file mode 100644 index 000000000..0d07fbf35 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la +else +plugin_LTLIBRARIES = libstrongswan-eap-dynamic.la +endif + +libstrongswan_eap_dynamic_la_SOURCES = \ + eap_dynamic_plugin.h eap_dynamic_plugin.c eap_dynamic.h eap_dynamic.c + +libstrongswan_eap_dynamic_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/eap_dynamic/Makefile.in b/src/libcharon/plugins/eap_dynamic/Makefile.in new file mode 100644 index 000000000..bf467ebeb --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/Makefile.in @@ -0,0 +1,621 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/eap_dynamic +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_eap_dynamic_la_LIBADD = +am_libstrongswan_eap_dynamic_la_OBJECTS = eap_dynamic_plugin.lo \ + eap_dynamic.lo +libstrongswan_eap_dynamic_la_OBJECTS = \ + $(am_libstrongswan_eap_dynamic_la_OBJECTS) +libstrongswan_eap_dynamic_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_eap_dynamic_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_eap_dynamic_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_eap_dynamic_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_eap_dynamic_la_SOURCES) +DIST_SOURCES = $(libstrongswan_eap_dynamic_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-eap-dynamic.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-eap-dynamic.la +libstrongswan_eap_dynamic_la_SOURCES = \ + eap_dynamic_plugin.h eap_dynamic_plugin.c eap_dynamic.h eap_dynamic.c + +libstrongswan_eap_dynamic_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/eap_dynamic/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/eap_dynamic/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-eap-dynamic.la: $(libstrongswan_eap_dynamic_la_OBJECTS) $(libstrongswan_eap_dynamic_la_DEPENDENCIES) + $(libstrongswan_eap_dynamic_la_LINK) $(am_libstrongswan_eap_dynamic_la_rpath) $(libstrongswan_eap_dynamic_la_OBJECTS) $(libstrongswan_eap_dynamic_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_dynamic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_dynamic_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c new file mode 100644 index 000000000..d24cbd128 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.c @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_dynamic.h" + +#include +#include + +typedef struct private_eap_dynamic_t private_eap_dynamic_t; + +/** + * Private data of an eap_dynamic_t object. + */ +struct private_eap_dynamic_t { + + /** + * Public authenticator_t interface. + */ + eap_dynamic_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * Our supported EAP types (as eap_vendor_type_t*) + */ + linked_list_t *types; + + /** + * EAP types supported by peer, if any + */ + linked_list_t *other_types; + + /** + * Prefer types sent by peer + */ + bool prefer_peer; + + /** + * The proxied EAP method + */ + eap_method_t *method; +}; + +/** + * Compare two eap_vendor_type_t objects + */ +static bool entry_matches(eap_vendor_type_t *item, eap_vendor_type_t *other) +{ + return item->type == other->type && item->vendor == other->vendor; +} + +/** + * Load the given EAP method + */ +static eap_method_t *load_method(private_eap_dynamic_t *this, + eap_type_t type, u_int32_t vendor) +{ + eap_method_t *method; + + method = charon->eap->create_instance(charon->eap, type, vendor, EAP_SERVER, + this->server, this->peer); + if (!method) + { + if (vendor) + { + DBG1(DBG_IKE, "loading vendor specific EAP method %d-%d failed", + type, vendor); + } + else + { + DBG1(DBG_IKE, "loading %N method failed", eap_type_names, type); + } + } + return method; +} + +/** + * Select the first method we can instantiate and is supported by both peers. + */ +static void select_method(private_eap_dynamic_t *this) +{ + eap_vendor_type_t *entry; + linked_list_t *outer = this->types, *inner = this->other_types; + char *who = "peer"; + + if (this->other_types && this->prefer_peer) + { + outer = this->other_types; + inner = this->types; + who = "us"; + } + + while (outer->remove_first(outer, (void*)&entry) == SUCCESS) + { + if (inner) + { + if (inner->find_first(inner, (void*)entry_matches, + NULL, entry) != SUCCESS) + { + if (entry->vendor) + { + DBG2(DBG_IKE, "proposed vendor specific EAP method %d-%d " + "not supported by %s, skipped", entry->type, + entry->vendor, who); + } + else + { + DBG2(DBG_IKE, "proposed %N method not supported by %s, " + "skipped", eap_type_names, entry->type, who); + } + free(entry); + continue; + } + } + this->method = load_method(this, entry->type, entry->vendor); + if (this->method) + { + if (entry->vendor) + { + DBG1(DBG_IKE, "vendor specific EAP method %d-%d selected", + entry->type, entry->vendor); + } + else + { + DBG1(DBG_IKE, "%N method selected", eap_type_names, + entry->type); + } + free(entry); + break; + } + free(entry); + } +} + +METHOD(eap_method_t, initiate, status_t, + private_eap_dynamic_t *this, eap_payload_t **out) +{ + if (!this->method) + { + select_method(this); + if (!this->method) + { + DBG1(DBG_IKE, "no supported EAP method found"); + return FAILED; + } + } + return this->method->initiate(this->method, out); +} + +METHOD(eap_method_t, process, status_t, + private_eap_dynamic_t *this, eap_payload_t *in, eap_payload_t **out) +{ + eap_type_t received_type, type; + u_int32_t received_vendor, vendor; + + received_type = in->get_type(in, &received_vendor); + if (received_vendor == 0 && received_type == EAP_NAK) + { + enumerator_t *enumerator; + + DBG1(DBG_IKE, "received %N, selecting a different EAP method", + eap_type_names, EAP_NAK); + + if (this->other_types) + { /* we already received a Nak or a proper response before */ + DBG1(DBG_IKE, "%N is not supported in this state", eap_type_names, + EAP_NAK); + return FAILED; + } + + this->other_types = linked_list_create(); + enumerator = in->get_types(in); + while (enumerator->enumerate(enumerator, &type, &vendor)) + { + eap_vendor_type_t *entry; + + if (!type) + { + DBG1(DBG_IKE, "peer does not support any other EAP methods"); + enumerator->destroy(enumerator); + return FAILED; + } + INIT(entry, + .type = type, + .vendor = vendor, + ); + this->other_types->insert_last(this->other_types, entry); + } + enumerator->destroy(enumerator); + + /* restart with a different method */ + this->method->destroy(this->method); + this->method = NULL; + return initiate(this, out); + } + if (!this->other_types) + { /* so we don't handle EAP-Naks later */ + this->other_types = linked_list_create(); + } + if (this->method) + { + return this->method->process(this->method, in, out); + } + return FAILED; +} + +METHOD(eap_method_t, get_type, eap_type_t, + private_eap_dynamic_t *this, u_int32_t *vendor) +{ + if (this->method) + { + return this->method->get_type(this->method, vendor); + } + *vendor = 0; + return EAP_DYNAMIC; +} + +METHOD(eap_method_t, get_msk, status_t, + private_eap_dynamic_t *this, chunk_t *msk) +{ + if (this->method) + { + return this->method->get_msk(this->method, msk); + } + return FAILED; +} + +METHOD(eap_method_t, get_identifier, u_int8_t, + private_eap_dynamic_t *this) +{ + if (this->method) + { + return this->method->get_identifier(this->method); + } + return 0; +} + +METHOD(eap_method_t, set_identifier, void, + private_eap_dynamic_t *this, u_int8_t identifier) +{ + if (this->method) + { + this->method->set_identifier(this->method, identifier); + } +} + +METHOD(eap_method_t, is_mutual, bool, + private_eap_dynamic_t *this) +{ + if (this->method) + { + return this->method->is_mutual(this->method); + } + return FALSE; +} + +METHOD(eap_method_t, destroy, void, + private_eap_dynamic_t *this) +{ + DESTROY_IF(this->method); + this->types->destroy_function(this->types, (void*)free); + DESTROY_FUNCTION_IF(this->other_types, (void*)free); + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/** + * Parse preferred EAP types + */ +static void handle_preferred_eap_types(private_eap_dynamic_t *this, + char *methods) +{ + enumerator_t *enumerator; + eap_vendor_type_t *type, *entry; + linked_list_t *preferred; + char *method; + + /* parse preferred EAP methods, format: type[-vendor], ... */ + preferred = linked_list_create(); + enumerator = enumerator_create_token(methods, ",", " "); + while (enumerator->enumerate(enumerator, &method)) + { + type = eap_vendor_type_from_string(method); + if (type) + { + preferred->insert_last(preferred, type); + } + } + enumerator->destroy(enumerator); + + enumerator = this->types->create_enumerator(this->types); + while (preferred->remove_last(preferred, (void**)&type) == SUCCESS) + { /* move (supported) types to the front, maintain the preferred order */ + this->types->reset_enumerator(this->types, enumerator); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry_matches(entry, type)) + { + this->types->remove_at(this->types, enumerator); + this->types->insert_first(this->types, entry); + break; + } + } + free(type); + } + enumerator->destroy(enumerator); + preferred->destroy(preferred); +} + +/** + * Get all supported EAP methods + */ +static void get_supported_eap_types(private_eap_dynamic_t *this) +{ + enumerator_t *enumerator; + eap_type_t type; + u_int32_t vendor; + + enumerator = charon->eap->create_enumerator(charon->eap, EAP_SERVER); + while (enumerator->enumerate(enumerator, &type, &vendor)) + { + eap_vendor_type_t *entry; + + INIT(entry, + .type = type, + .vendor = vendor, + ); + this->types->insert_last(this->types, entry); + } + enumerator->destroy(enumerator); +} + +/* + * Defined in header + */ +eap_dynamic_t *eap_dynamic_create(identification_t *server, + identification_t *peer) +{ + private_eap_dynamic_t *this; + char *preferred; + + INIT(this, + .public = { + .interface = { + .initiate = _initiate, + .process = _process, + .get_type = _get_type, + .is_mutual = _is_mutual, + .get_msk = _get_msk, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + .server = server->clone(server), + .types = linked_list_create(), + .prefer_peer = lib->settings->get_bool(lib->settings, + "%s.plugins.eap-dynamic.prefer_peer", FALSE, charon->name), + ); + + /* get all supported EAP methods */ + get_supported_eap_types(this); + /* move preferred methods to the front */ + preferred = lib->settings->get_str(lib->settings, + "%s.plugins.eap-dynamic.preferred", NULL, charon->name); + if (preferred) + { + handle_preferred_eap_types(this, preferred); + } + return &this->public; +} diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h new file mode 100644 index 000000000..35db4fa26 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_dynamic_i eap_dynamic + * @{ @ingroup eap_dynamic + */ + +#ifndef EAP_DYNAMIC_H_ +#define EAP_DYNAMIC_H_ + +typedef struct eap_dynamic_t eap_dynamic_t; + +#include + +/** + * Implementation of the eap_method_t interface for a virtual EAP method that + * proxies other EAP methods and supports the selection of the actual method + * by the client. + */ +struct eap_dynamic_t { + + /** + * Implemented eap_method_t interface + */ + eap_method_t interface; +}; + +/** + * Create a dynamic EAP proxy serving any supported real method which is also + * supported (or selected) by the client. + * + * @param server ID of the EAP server + * @param peer ID of the EAP client + * @return eap_dynamic_t object + */ +eap_dynamic_t *eap_dynamic_create(identification_t *server, + identification_t *peer); + +#endif /** EAP_DYNAMIC_H_ @}*/ diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c new file mode 100644 index 000000000..d6f38b666 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_dynamic_plugin.h" + +#include "eap_dynamic.h" + +#include + +METHOD(plugin_t, get_name, char*, + eap_dynamic_plugin_t *this) +{ + return "eap-dynamic"; +} + +METHOD(plugin_t, get_features, int, + eap_dynamic_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(eap_method_register, eap_dynamic_create), + PLUGIN_PROVIDE(EAP_SERVER, EAP_DYNAMIC), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + eap_dynamic_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *eap_dynamic_plugin_create() +{ + eap_dynamic_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} + diff --git a/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h new file mode 100644 index 000000000..9b124d8d2 --- /dev/null +++ b/src/libcharon/plugins/eap_dynamic/eap_dynamic_plugin.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_dynamic eap_dynamic + * @ingroup cplugins + * + * @defgroup eap_dynamic_plugin eap_dynamic_plugin + * @{ @ingroup eap_dynamic + */ + +#ifndef EAP_DYNAMIC_PLUGIN_H_ +#define EAP_DYNAMIC_PLUGIN_H_ + +#include + +typedef struct eap_dynamic_plugin_t eap_dynamic_plugin_t; + +/** + * EAP plugin that can use any supported EAP method the client supports or + * prefers to use. + */ +struct eap_dynamic_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** EAP_DYNAMIC_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/eap_gtc/Makefile.am b/src/libcharon/plugins/eap_gtc/Makefile.am index d8722bf9d..e4234fab2 100644 --- a/src/libcharon/plugins/eap_gtc/Makefile.am +++ b/src/libcharon/plugins/eap_gtc/Makefile.am @@ -13,4 +13,4 @@ endif libstrongswan_eap_gtc_la_SOURCES = \ eap_gtc_plugin.h eap_gtc_plugin.c eap_gtc.h eap_gtc.c -libstrongswan_eap_gtc_la_LDFLAGS = -module -avoid-version -lpam +libstrongswan_eap_gtc_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/eap_gtc/Makefile.in b/src/libcharon/plugins/eap_gtc/Makefile.in index b3f989e38..8a334983b 100644 --- a/src/libcharon/plugins/eap_gtc/Makefile.in +++ b/src/libcharon/plugins/eap_gtc/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_eap_gtc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_gtc_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_gtc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -291,7 +297,7 @@ AM_CFLAGS = -rdynamic libstrongswan_eap_gtc_la_SOURCES = \ eap_gtc_plugin.h eap_gtc_plugin.c eap_gtc.h eap_gtc.c -libstrongswan_eap_gtc_la_LDFLAGS = -module -avoid-version -lpam +libstrongswan_eap_gtc_la_LDFLAGS = -module -avoid-version all: all-am .SUFFIXES: diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.c b/src/libcharon/plugins/eap_gtc/eap_gtc.c index c3ab07de0..f090e94a8 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc.c +++ b/src/libcharon/plugins/eap_gtc/eap_gtc.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007 Martin Willi + * Copyright (C) 2007-2012 Martin Willi + * Copyright (C) 2012 revosec AG * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -17,12 +18,8 @@ #include #include -#include - -#include #define GTC_REQUEST_MSG "password" -#define GTC_PAM_SERVICE "login" typedef struct private_eap_gtc_t private_eap_gtc_t; @@ -77,63 +74,6 @@ METHOD(eap_method_t, initiate_peer, status_t, return FAILED; } -/** - * PAM conv callback function - */ -static int auth_conv(int num_msg, const struct pam_message **msg, - struct pam_response **resp, char *password) -{ - struct pam_response *response; - - if (num_msg != 1) - { - return PAM_CONV_ERR; - } - response = malloc(sizeof(struct pam_response)); - response->resp = strdup(password); - response->resp_retcode = 0; - *resp = response; - return PAM_SUCCESS; -} - -/** - * Authenticate a username/password using PAM - */ -static bool authenticate(char *service, char *user, char *password) -{ - pam_handle_t *pamh = NULL; - static struct pam_conv conv; - int ret; - - conv.conv = (void*)auth_conv; - conv.appdata_ptr = password; - - ret = pam_start(service, user, &conv, &pamh); - if (ret != PAM_SUCCESS) - { - DBG1(DBG_IKE, "EAP-GTC pam_start failed: %s", - pam_strerror(pamh, ret)); - return FALSE; - } - ret = pam_authenticate(pamh, 0); - if (ret == PAM_SUCCESS) - { - ret = pam_acct_mgmt(pamh, 0); - if (ret != PAM_SUCCESS) - { - DBG1(DBG_IKE, "EAP-GTC pam_acct_mgmt failed: %s", - pam_strerror(pamh, ret)); - } - } - else - { - DBG1(DBG_IKE, "EAP-GTC pam_authenticate failed: %s", - pam_strerror(pamh, ret)); - } - pam_end(pamh, ret); - return ret == PAM_SUCCESS; -} - METHOD(eap_method_t, initiate_server, status_t, private_eap_gtc_t *this, eap_payload_t **out) { @@ -192,39 +132,57 @@ METHOD(eap_method_t, process_peer, status_t, METHOD(eap_method_t, process_server, status_t, private_eap_gtc_t *this, eap_payload_t *in, eap_payload_t **out) { - chunk_t data, encoding; - char *user, *password, *service, *pos; - - data = chunk_skip(in->get_data(in), 5); - if (this->identifier != in->get_identifier(in) || !data.len) + status_t status = FAILED; + chunk_t user, pass; + xauth_method_t *xauth; + cp_payload_t *ci, *co; + char *backend; + + user = this->peer->get_encoding(this->peer); + pass = chunk_skip(in->get_data(in), 5); + if (this->identifier != in->get_identifier(in) || !pass.len) { DBG1(DBG_IKE, "received invalid EAP-GTC message"); return FAILED; } - encoding = this->peer->get_encoding(this->peer); - /* if a RFC822_ADDR id is provided, we use the username part only */ - pos = memchr(encoding.ptr, '@', encoding.len); - if (pos) + /* get XAuth backend to use for credential verification. Default to PAM + * to support legacy EAP-GTC configurations */ + backend = lib->settings->get_str(lib->settings, + "%s.plugins.eap-gtc.backend", "pam", charon->name); + xauth = charon->xauth->create_instance(charon->xauth, backend, XAUTH_SERVER, + this->server, this->peer); + if (!xauth) { - encoding.len = (u_char*)pos - encoding.ptr; + DBG1(DBG_IKE, "creating EAP-GTC XAuth backend '%s' failed", backend); + return FAILED; } - user = alloca(encoding.len + 1); - memcpy(user, encoding.ptr, encoding.len); - user[encoding.len] = '\0'; - - password = alloca(data.len + 1); - memcpy(password, data.ptr, data.len); - password[data.len] = '\0'; - - service = lib->settings->get_str(lib->settings, - "charon.plugins.eap-gtc.pam_service", GTC_PAM_SERVICE); - - if (!authenticate(service, user, password)) + if (xauth->initiate(xauth, &co) == NEED_MORE) { - return FAILED; + /* assume that "out" contains username/password attributes */ + co->destroy(co); + ci = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + ci->add_attribute(ci, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); + ci->add_attribute(ci, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); + switch (xauth->process(xauth, ci, &co)) + { + case SUCCESS: + status = SUCCESS; + break; + case NEED_MORE: + /* TODO: multiple exchanges currently not supported */ + co->destroy(co); + break; + case FAILED: + default: + break; + } + ci->destroy(ci); } - return SUCCESS; + xauth->destroy(xauth); + return status; } METHOD(eap_method_t, get_type, eap_type_t, diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.h b/src/libcharon/plugins/eap_gtc/eap_gtc.h index 2eb8482f8..4dac53cfb 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc.h +++ b/src/libcharon/plugins/eap_gtc/eap_gtc.h @@ -23,7 +23,7 @@ typedef struct eap_gtc_t eap_gtc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-GTC. diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc_plugin.c b/src/libcharon/plugins/eap_gtc/eap_gtc_plugin.c index bd70b757a..d579eaa5a 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc_plugin.c +++ b/src/libcharon/plugins/eap_gtc/eap_gtc_plugin.c @@ -19,9 +19,6 @@ #include -/* missing in cababilities.h */ -#define CAP_AUDIT_WRITE 29 - METHOD(plugin_t, get_name, char*, eap_gtc_plugin_t *this) { @@ -62,14 +59,6 @@ plugin_t *eap_gtc_plugin_create() }, ); - /* required for PAM authentication */ - charon->keep_cap(charon, CAP_AUDIT_WRITE); - - charon->eap->add_method(charon->eap, EAP_GTC, 0, EAP_SERVER, - (eap_constructor_t)eap_gtc_create_server); - charon->eap->add_method(charon->eap, EAP_GTC, 0, EAP_PEER, - (eap_constructor_t)eap_gtc_create_peer); - return &this->plugin; } diff --git a/src/libcharon/plugins/eap_identity/Makefile.in b/src/libcharon/plugins/eap_identity/Makefile.in index b348b5fb5..2f4494c39 100644 --- a/src/libcharon/plugins/eap_identity/Makefile.in +++ b/src/libcharon/plugins/eap_identity/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_eap_identity_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_identity_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_identity_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_identity/eap_identity.h b/src/libcharon/plugins/eap_identity/eap_identity.h index 9a7f28574..4e7f6fd9d 100644 --- a/src/libcharon/plugins/eap_identity/eap_identity.h +++ b/src/libcharon/plugins/eap_identity/eap_identity.h @@ -23,7 +23,7 @@ typedef struct eap_identity_t eap_identity_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP Identity. diff --git a/src/libcharon/plugins/eap_md5/Makefile.in b/src/libcharon/plugins/eap_md5/Makefile.in index 209753b2d..dcf95198f 100644 --- a/src/libcharon/plugins/eap_md5/Makefile.in +++ b/src/libcharon/plugins/eap_md5/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_eap_md5_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_md5_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_md5_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_md5/eap_md5.c b/src/libcharon/plugins/eap_md5/eap_md5.c index b0a234527..b2640d104 100644 --- a/src/libcharon/plugins/eap_md5/eap_md5.c +++ b/src/libcharon/plugins/eap_md5/eap_md5.c @@ -100,7 +100,11 @@ static status_t hash_challenge(private_eap_md5_t *this, chunk_t *response, DBG1(DBG_IKE, "EAP-MD5 failed, MD5 not supported"); return FAILED; } - hasher->allocate_hash(hasher, concat, response); + if (!hasher->allocate_hash(hasher, concat, response)) + { + hasher->destroy(hasher); + return FAILED; + } hasher->destroy(hasher); return SUCCESS; } @@ -119,11 +123,11 @@ METHOD(eap_method_t, initiate_server, status_t, eap_md5_header_t *req; rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge)) { + DESTROY_IF(rng); return FAILED; } - rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge); rng->destroy(rng); req = alloca(PAYLOAD_LEN); diff --git a/src/libcharon/plugins/eap_md5/eap_md5.h b/src/libcharon/plugins/eap_md5/eap_md5.h index c6687149a..5396535e1 100644 --- a/src/libcharon/plugins/eap_md5/eap_md5.h +++ b/src/libcharon/plugins/eap_md5/eap_md5.h @@ -23,7 +23,7 @@ typedef struct eap_md5_t eap_md5_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MD5 (CHAP). diff --git a/src/libcharon/plugins/eap_mschapv2/Makefile.in b/src/libcharon/plugins/eap_mschapv2/Makefile.in index 6d3d7f8db..e954396ec 100644 --- a/src/libcharon/plugins/eap_mschapv2/Makefile.in +++ b/src/libcharon/plugins/eap_mschapv2/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_eap_mschapv2_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_mschapv2_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_mschapv2_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c index 9dfc69205..0d71c3d97 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.c @@ -281,7 +281,11 @@ static status_t NtPasswordHash(chunk_t password, chunk_t *password_hash) DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no MD4 hasher available"); return FAILED; } - hasher->allocate_hash(hasher, password, password_hash); + if (!hasher->allocate_hash(hasher, password, password_hash)) + { + hasher->destroy(hasher); + return FAILED; + } hasher->destroy(hasher); return SUCCESS; } @@ -302,7 +306,11 @@ static status_t ChallengeHash(chunk_t peer_challenge, chunk_t server_challenge, return FAILED; } concat = chunk_cata("ccc", peer_challenge, server_challenge, username); - hasher->allocate_hash(hasher, concat, challenge_hash); + if (!hasher->allocate_hash(hasher, concat, challenge_hash)) + { + hasher->destroy(hasher); + return FAILED; + } hasher->destroy(hasher); /* we need only the first 8 octets */ challenge_hash->len = 8; @@ -337,9 +345,15 @@ static status_t ChallengeResponse(chunk_t challenge_hash, chunk_t password_hash, for (i = 0; i < 3; i++) { chunk_t expanded, encrypted; + expanded = ExpandDESKey(keys[i]); - crypter->set_key(crypter, expanded); - crypter->encrypt(crypter, challenge_hash, chunk_empty, &encrypted); + if (!crypter->set_key(crypter, expanded) || + !crypter->encrypt(crypter, challenge_hash, chunk_empty, &encrypted)) + { + chunk_clear(&expanded); + crypter->destroy(crypter); + return FAILED; + } memcpy(&response->ptr[i * 8], encrypted.ptr, encrypted.len); chunk_clear(&encrypted); chunk_clear(&expanded); @@ -376,10 +390,17 @@ static status_t AuthenticatorResponse(chunk_t password_hash_hash, } concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1); - hasher->allocate_hash(hasher, concat, &digest); + if (!hasher->allocate_hash(hasher, concat, &digest)) + { + hasher->destroy(hasher); + return FAILED; + } concat = chunk_cata("ccc", digest, challenge_hash, magic2); - hasher->allocate_hash(hasher, concat, response); - + if (!hasher->allocate_hash(hasher, concat, response)) + { + hasher->destroy(hasher); + return FAILED; + } hasher->destroy(hasher); chunk_free(&digest); return SUCCESS; @@ -428,7 +449,9 @@ static status_t GenerateMSK(chunk_t password_hash_hash, chunk_t keypad = chunk_from_chars( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - chunk_t concat, master_key, master_receive_key, master_send_key; + char master_key[HASH_SIZE_SHA1]; + char master_receive_key[HASH_SIZE_SHA1], master_send_key[HASH_SIZE_SHA1]; + chunk_t concat, master; hasher_t *hasher; hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); @@ -439,23 +462,29 @@ static status_t GenerateMSK(chunk_t password_hash_hash, } concat = chunk_cata("ccc", password_hash_hash, nt_response, magic1); - hasher->allocate_hash(hasher, concat, &master_key); - master_key.len = 16; - - concat = chunk_cata("cccc", master_key, shapad1, magic2, shapad2); - hasher->allocate_hash(hasher, concat, &master_receive_key); - master_receive_key.len = 16; - - concat = chunk_cata("cccc", master_key, shapad1, magic3, shapad2); - hasher->allocate_hash(hasher, concat, &master_send_key); - master_send_key.len = 16; + if (!hasher->get_hash(hasher, concat, master_key)) + { + hasher->destroy(hasher); + return FAILED; + } + master = chunk_create(master_key, 16); + concat = chunk_cata("cccc", master, shapad1, magic2, shapad2); + if (!hasher->get_hash(hasher, concat, master_receive_key)) + { + hasher->destroy(hasher); + return FAILED; + } + concat = chunk_cata("cccc", master, shapad1, magic3, shapad2); + if (!hasher->get_hash(hasher, concat, master_send_key)) + { + hasher->destroy(hasher); + return FAILED; + } - *msk = chunk_cat("cccc", master_receive_key, master_send_key, keypad, keypad); + *msk = chunk_cat("cccc", chunk_create(master_receive_key, 16), + chunk_create(master_send_key, 16), keypad, keypad); hasher->destroy(hasher); - chunk_free(&master_key); - chunk_free(&master_receive_key); - chunk_free(&master_send_key); return SUCCESS; } @@ -533,13 +562,12 @@ static char* sanitize(char *str) /** * Returns a chunk of just the username part of the given user identity. - * Note: the chunk points to internal data of the identification. + * Note: the chunk points to internal data of the given chunk */ -static chunk_t extract_username(identification_t* identification) +static chunk_t extract_username(chunk_t id) { char *has_domain; - chunk_t id; - id = identification->get_encoding(identification); + has_domain = (char*)memchr(id.ptr, '\\', id.len); if (has_domain) { @@ -577,12 +605,12 @@ METHOD(eap_method_t, initiate_server, status_t, u_int16_t len = CHALLENGE_PAYLOAD_LEN + sizeof(MSCHAPV2_HOST_NAME) - 1; rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge)) { - DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG"); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no challenge"); + DESTROY_IF(rng); return FAILED; } - rng->allocate_bytes(rng, CHALLENGE_LEN, &this->challenge); rng->destroy(rng); eap = alloca(len); @@ -645,7 +673,7 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, eap_mschapv2_header_t *eap; eap_mschapv2_challenge_t *cha; eap_mschapv2_response_t *res; - chunk_t data, peer_challenge, username, nt_hash; + chunk_t data, peer_challenge, userid, username, nt_hash; u_int16_t len = RESPONSE_PAYLOAD_LEN; data = in->get_data(in); @@ -670,14 +698,14 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, this->mschapv2id = eap->ms_chapv2_id; this->challenge = chunk_clone(chunk_create(cha->challenge, CHALLENGE_LEN)); + peer_challenge = chunk_alloca(CHALLENGE_LEN); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr)) { - DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG"); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed"); + DESTROY_IF(rng); return FAILED; } - peer_challenge = chunk_alloca(CHALLENGE_LEN); - rng->get_bytes(rng, CHALLENGE_LEN, peer_challenge.ptr); rng->destroy(rng); if (!get_nt_hash(this, this->peer, this->server, &nt_hash)) @@ -687,8 +715,11 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, return NOT_FOUND; } - username = extract_username(this->peer); - len += username.len; + /* we transmit the whole user identity (including the domain part) but + * only use the user part when calculating the challenge hash */ + userid = this->peer->get_encoding(this->peer); + len += userid.len; + username = extract_username(userid); if (GenerateStuff(this, this->challenge, peer_challenge, username, nt_hash) != SUCCESS) @@ -713,9 +744,7 @@ static status_t process_peer_challenge(private_eap_mschapv2_t *this, memset(&res->response, 0, RESPONSE_LEN); memcpy(res->response.peer_challenge, peer_challenge.ptr, peer_challenge.len); memcpy(res->response.nt_response, this->nt_response.ptr, this->nt_response.len); - - username = this->peer->get_encoding(this->peer); - memcpy(res->name, username.ptr, username.len); + memcpy(res->name, userid.ptr, userid.len); *out = eap_payload_create_data(chunk_create((void*) eap, len)); return NEED_MORE; @@ -964,12 +993,12 @@ static status_t process_server_retry(private_eap_mschapv2_t *this, DBG1(DBG_IKE, "EAP-MS-CHAPv2 verification failed, retry (%d)", this->retries); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr)) { - DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, no RNG"); + DBG1(DBG_IKE, "EAP-MS-CHAPv2 failed, allocating challenge failed"); + DESTROY_IF(rng); return FAILED; } - rng->get_bytes(rng, CHALLENGE_LEN, this->challenge.ptr); rng->destroy(rng); chunk_free(&this->nt_response); @@ -1026,7 +1055,8 @@ static status_t process_server_response(private_eap_mschapv2_t *this, snprintf(buf, sizeof(buf), "%.*s", name_len, res->name); userid = identification_create_from_string(buf); DBG2(DBG_IKE, "EAP-MS-CHAPv2 username: '%Y'", userid); - username = extract_username(userid); + /* userid can only be destroyed after the last use of username */ + username = extract_username(userid->get_encoding(userid)); if (!get_nt_hash(this, this->server, userid, &nt_hash)) { diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h index 34cc1141e..0e7abc397 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h @@ -23,7 +23,7 @@ typedef struct eap_mschapv2_t eap_mschapv2_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MS-CHAPv2. diff --git a/src/libcharon/plugins/eap_peap/Makefile.in b/src/libcharon/plugins/eap_peap/Makefile.in index 4f860e175..82aa990ae 100644 --- a/src/libcharon/plugins/eap_peap/Makefile.in +++ b/src/libcharon/plugins/eap_peap/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_eap_peap_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_peap_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_peap_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_peap/eap_peap.c b/src/libcharon/plugins/eap_peap/eap_peap.c index bd426bba7..8aba703c5 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap.c +++ b/src/libcharon/plugins/eap_peap/eap_peap.c @@ -156,16 +156,19 @@ static eap_peap_t *eap_peap_create(private_eap_peap_t * this, tls_t *tls; if (is_server && !lib->settings->get_bool(lib->settings, - "charon.plugins.eap-peap.request_peer_auth", FALSE)) + "%s.plugins.eap-peap.request_peer_auth", FALSE, + charon->name)) { peer = NULL; } frag_size = lib->settings->get_int(lib->settings, - "charon.plugins.eap-peap.fragment_size", MAX_FRAGMENT_LEN); + "%s.plugins.eap-peap.fragment_size", MAX_FRAGMENT_LEN, + charon->name); max_msg_count = lib->settings->get_int(lib->settings, - "charon.plugins.eap-peap.max_message_count", MAX_MESSAGE_COUNT); + "%s.plugins.eap-peap.max_message_count", MAX_MESSAGE_COUNT, + charon->name); include_length = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-peap.include_length", FALSE); + "%s.plugins.eap-peap.include_length", FALSE, charon->name); tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_PEAP, application, NULL); this->tls_eap = tls_eap_create(EAP_PEAP, tls, frag_size, max_msg_count, @@ -180,7 +183,7 @@ static eap_peap_t *eap_peap_create(private_eap_peap_t * this, } eap_peap_t *eap_peap_create_server(identification_t *server, - identification_t *peer) + identification_t *peer) { private_eap_peap_t *eap_peap; eap_method_t *eap_method; diff --git a/src/libcharon/plugins/eap_peap/eap_peap.h b/src/libcharon/plugins/eap_peap/eap_peap.h index f47bad561..2756ad3e6 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap.h +++ b/src/libcharon/plugins/eap_peap/eap_peap.h @@ -23,7 +23,7 @@ typedef struct eap_peap_t eap_peap_t; -#include +#include /** * Implementation of eap_method_t using EAP-PEAP. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.c b/src/libcharon/plugins/eap_peap/eap_peap_peer.c index 72e201fb6..79fd667cb 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.c @@ -85,7 +85,7 @@ METHOD(tls_application_t, process, status_t, default: return FAILED; } - + in = eap_payload_create_data(data); DBG3(DBG_IKE, "%B", &data); chunk_free(&data); @@ -151,7 +151,8 @@ METHOD(tls_application_t, process, status_t, if (!this->ph2_method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in)); + this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, + in->is_expanded(in)); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.h b/src/libcharon/plugins/eap_peap/eap_peap_peer.h index a87544209..196d4e2c4 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.h @@ -26,7 +26,7 @@ typedef struct eap_peap_peer_t eap_peap_peer_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as peer. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.c b/src/libcharon/plugins/eap_peap/eap_peap_server.c index 4acdd9f07..0e8046501 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_server.c +++ b/src/libcharon/plugins/eap_peap/eap_peap_server.c @@ -91,7 +91,8 @@ static status_t start_phase2_auth(private_eap_peap_server_t *this) eap_type_t type; eap_type_str = lib->settings->get_str(lib->settings, - "charon.plugins.eap-peap.phase2_method", "mschapv2"); + "%s.plugins.eap-peap.phase2_method", "mschapv2", + charon->name); type = eap_type_from_string(eap_type_str); if (type == 0) { @@ -128,7 +129,7 @@ static status_t start_phase2_auth(private_eap_peap_server_t *this) static status_t start_phase2_tnc(private_eap_peap_server_t *this) { if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings, - "charon.plugins.eap-peap.phase2_tnc", FALSE)) + "%s.plugins.eap-peap.phase2_tnc", FALSE, charon->name)) { DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, EAP_TNC); this->ph2_method = charon->eap->create_instance(charon->eap, EAP_TNC, @@ -197,7 +198,7 @@ METHOD(tls_application_t, process, status_t, { received_type = in->get_type(in, &received_vendor); DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N/%N]", - eap_code_short_names, code, + eap_code_short_names, code, eap_type_short_names, received_type); if (code != EAP_RESPONSE) { @@ -209,7 +210,7 @@ METHOD(tls_application_t, process, status_t, else { DBG1(DBG_IKE, "received tunneled EAP-PEAP AVP [EAP/%N]", - eap_code_short_names, code); + eap_code_short_names, code); /* if EAP_SUCCESS check if to continue phase2 with EAP-TNC */ return (this->phase2_result == EAP_SUCCESS && code == EAP_SUCCESS) ? @@ -273,7 +274,7 @@ METHOD(tls_application_t, process, status_t, /* Start Phase 2 of EAP-PEAP authentication */ if (lib->settings->get_bool(lib->settings, - "charon.plugins.eap-peap.request_peer_auth", FALSE)) + "%s.plugins.eap-peap.request_peer_auth", FALSE, charon->name)) { return start_phase2_tnc(this); } @@ -302,10 +303,10 @@ METHOD(tls_application_t, process, status_t, this->ph2_method->destroy(this->ph2_method); this->ph2_method = NULL; - /* EAP-PEAP requires the sending of an inner EAP_SUCCESS message */ - this->phase2_result = EAP_SUCCESS; + /* EAP-PEAP requires the sending of an inner EAP_SUCCESS message */ + this->phase2_result = EAP_SUCCESS; this->out = eap_payload_create_code(this->phase2_result, 1 + - this->ph1_method->get_identifier(this->ph1_method)); + this->ph1_method->get_identifier(this->ph1_method)); return NEED_MORE; case NEED_MORE: break; @@ -321,9 +322,9 @@ METHOD(tls_application_t, process, status_t, DBG1(DBG_IKE, "%N method failed", eap_type_names, type); } /* EAP-PEAP requires the sending of an inner EAP_FAILURE message */ - this->phase2_result = EAP_FAILURE; + this->phase2_result = EAP_FAILURE; this->out = eap_payload_create_code(this->phase2_result, 1 + - this->ph1_method->get_identifier(this->ph1_method)); + this->ph1_method->get_identifier(this->ph1_method)); return NEED_MORE; } return status; @@ -360,7 +361,7 @@ METHOD(tls_application_t, build, status_t, this->ph2_method->initiate(this->ph2_method, &this->out); this->start_phase2 = FALSE; } - + this->start_phase2_id = TRUE; if (this->out) @@ -423,7 +424,8 @@ eap_peap_server_t *eap_peap_server_create(identification_t *server, .start_phase2 = TRUE, .start_phase2_tnc = TRUE, .start_phase2_id = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-peap.phase2_piggyback", FALSE), + "%s.plugins.eap-peap.phase2_piggyback", + FALSE, charon->name), .phase2_result = EAP_FAILURE, .avp = eap_peap_avp_create(TRUE), ); diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.h b/src/libcharon/plugins/eap_peap/eap_peap_server.h index 93141d62b..4585a622a 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_server.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_server.h @@ -26,7 +26,7 @@ typedef struct eap_peap_server_t eap_peap_server_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as server. diff --git a/src/libcharon/plugins/eap_radius/Makefile.in b/src/libcharon/plugins/eap_radius/Makefile.in index 0bef44042..1bdf24c2c 100644 --- a/src/libcharon/plugins/eap_radius/Makefile.in +++ b/src/libcharon/plugins/eap_radius/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_eap_radius_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_radius_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_radius_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c index c0a3703b6..870ed1fc0 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.c +++ b/src/libcharon/plugins/eap_radius/eap_radius.c @@ -264,7 +264,7 @@ static void process_filter_id(private_eap_radius_t *this, radius_message_t *msg) case RAT_FILTER_ID: filter_id = data; DBG1(DBG_IKE, "received RADIUS attribute Filter-Id: " - "'%.*s'", filter_id.len, filter_id.ptr); + "'%.*s'", (int)filter_id.len, filter_id.ptr); break; default: break; @@ -453,14 +453,17 @@ eap_radius_t *eap_radius_create(identification_t *server, identification_t *peer /* initially EAP_RADIUS, but is set to the method selected by RADIUS */ .type = EAP_RADIUS, .eap_start = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-radius.eap_start", FALSE), + "%s.plugins.eap-radius.eap_start", FALSE, + charon->name), .id_prefix = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.id_prefix", ""), + "%s.plugins.eap-radius.id_prefix", "", + charon->name), .class_group = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-radius.class_group", FALSE), + "%s.plugins.eap-radius.class_group", FALSE, + charon->name), .filter_id = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-radius.filter_id", FALSE), - + "%s.plugins.eap-radius.filter_id", FALSE, + charon->name), ); this->client = eap_radius_create_client(); if (!this->client) diff --git a/src/libcharon/plugins/eap_radius/eap_radius.h b/src/libcharon/plugins/eap_radius/eap_radius.h index e98cb06e3..875543554 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.h +++ b/src/libcharon/plugins/eap_radius/eap_radius.h @@ -23,7 +23,7 @@ typedef struct eap_radius_t eap_radius_t; -#include +#include /** * Implementation of the eap_method_t interface using a RADIUS server. diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c index 45be22704..f164f67ed 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c @@ -149,6 +149,7 @@ static bool send_message(private_eap_radius_accounting_t *this, */ static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa) { + enumerator_t *enumerator; host_t *vip; char buf[64]; chunk_t data; @@ -157,18 +158,27 @@ static void add_ike_sa_parameters(radius_message_t *message, ike_sa_t *ike_sa) message->add(message, RAT_USER_NAME, chunk_create(buf, strlen(buf))); snprintf(buf, sizeof(buf), "%#H", ike_sa->get_other_host(ike_sa)); message->add(message, RAT_CALLING_STATION_ID, chunk_create(buf, strlen(buf))); - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip && vip->get_family(vip) == AF_INET) - { - message->add(message, RAT_FRAMED_IP_ADDRESS, vip->get_address(vip)); - } - if (vip && vip->get_family(vip) == AF_INET6) + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (enumerator->enumerate(enumerator, &vip)) { - /* we currently assign /128 prefixes, only (reserved, length) */ - data = chunk_from_chars(0, 128); - data = chunk_cata("cc", data, vip->get_address(vip)); - message->add(message, RAT_FRAMED_IPV6_PREFIX, data); + switch (vip->get_family(vip)) + { + case AF_INET: + message->add(message, RAT_FRAMED_IP_ADDRESS, + vip->get_address(vip)); + break; + case AF_INET6: + /* we currently assign /128 prefixes, only (reserved, length) */ + data = chunk_from_chars(0, 128); + data = chunk_cata("cc", data, vip->get_address(vip)); + message->add(message, RAT_FRAMED_IPV6_PREFIX, data); + break; + default: + break; + } } + enumerator->destroy(enumerator); } /** @@ -197,9 +207,9 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa) this->mutex->lock(this->mutex); entry = this->sessions->put(this->sessions, (void*)(uintptr_t)id, entry); this->mutex->unlock(this->mutex); - free(entry); } message->destroy(message); + free(entry); } /** @@ -271,14 +281,22 @@ METHOD(listener_t, ike_updown, bool, METHOD(listener_t, message_hook, bool, private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { /* start accounting here, virtual IP now is set */ - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && - message->get_exchange_type(message) == IKE_AUTH && + if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && !incoming && !message->get_request(message)) { - send_start(this, ike_sa); + if (ike_sa->get_version(ike_sa) == IKEV1 && + message->get_exchange_type(message) == TRANSACTION) + { + send_start(this, ike_sa); + } + if (ike_sa->get_version(ike_sa) == IKEV2 && + message->get_exchange_type(message) == IKE_AUTH) + { + send_start(this, ike_sa); + } } return TRUE; } diff --git a/src/libcharon/plugins/eap_radius/eap_radius_dae.c b/src/libcharon/plugins/eap_radius/eap_radius_dae.c index e84fe5b9c..2ea2b059c 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_dae.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_dae.c @@ -52,11 +52,6 @@ struct private_eap_radius_dae_t { */ int fd; - /** - * Listen job - */ - callback_job_t *job; - /** * RADIUS shared secret for DAE exchanges */ @@ -189,11 +184,16 @@ static void send_response(private_eap_radius_dae_t *this, response = radius_message_create(code); response->set_identifier(response, request->get_identifier(request)); - response->sign(response, request->get_authenticator(request), - this->secret, this->hasher, this->signer, NULL, FALSE); - - send_message(this, response, client); - save_retransmit(this, response, client); + if (response->sign(response, request->get_authenticator(request), + this->secret, this->hasher, this->signer, NULL, FALSE)) + { + send_message(this, response, client); + save_retransmit(this, response, client); + } + else + { + response->destroy(response); + } } /** @@ -456,9 +456,11 @@ static bool open_socket(private_eap_radius_dae_t *this) host = host_create_from_string( lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.dae.listen", "0.0.0.0"), + "%s.plugins.eap-radius.dae.listen", "0.0.0.0", + charon->name), lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.dae.port", RADIUS_DAE_PORT)); + "%s.plugins.eap-radius.dae.port", RADIUS_DAE_PORT, + charon->name)); if (!host) { DBG1(DBG_CFG, "invalid RADIUS DAE listen address"); @@ -479,10 +481,6 @@ static bool open_socket(private_eap_radius_dae_t *this) METHOD(eap_radius_dae_t, destroy, void, private_eap_radius_dae_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } if (this->fd != -1) { close(this->fd); @@ -508,7 +506,8 @@ eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting) .fd = -1, .secret = { .ptr = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.dae.secret", NULL), + "%s.plugins.eap-radius.dae.secret", NULL, + charon->name), }, .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128), @@ -527,17 +526,16 @@ eap_radius_dae_t *eap_radius_dae_create(eap_radius_accounting_t *accounting) return NULL; } this->secret.len = strlen(this->secret.ptr); - this->signer->set_key(this->signer, this->secret); - - if (!open_socket(this)) + if (!this->signer->set_key(this->signer, this->secret) || + !open_socket(this)) { destroy(this); return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/eap_radius/eap_radius_forward.c b/src/libcharon/plugins/eap_radius/eap_radius_forward.c index cb4ca74e3..2dd38ea2f 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_forward.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_forward.c @@ -319,11 +319,11 @@ void eap_radius_forward_to_ike(radius_message_t *response) METHOD(listener_t, message, bool, private_eap_radius_forward_t *this, - ike_sa_t *ike_sa, message_t *message, bool incoming) + ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain) { linked_list_t *queue; - if (message->get_exchange_type(message) == IKE_AUTH) + if (plain && message->get_exchange_type(message) == IKE_AUTH) { if (incoming) { @@ -436,9 +436,11 @@ eap_radius_forward_t *eap_radius_forward_create() .destroy = _destroy, }, .from_attr = parse_selector(lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.forward.ike_to_radius", "")), + "%s.plugins.eap-radius.forward.ike_to_radius", "", + charon->name)), .to_attr = parse_selector(lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.forward.radius_to_ike", "")), + "%s.plugins.eap-radius.forward.radius_to_ike", "", + charon->name)), .from = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 8), .to = hashtable_create((hashtable_hash_t)hash, diff --git a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c index 8ee0ab81a..9d4bbe1f3 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius_plugin.c +++ b/src/libcharon/plugins/eap_radius/eap_radius_plugin.c @@ -90,22 +90,23 @@ static void load_configs(private_eap_radius_plugin_t *this) int auth_port, acct_port, sockets, preference; address = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.server", NULL); + "%s.plugins.eap-radius.server", NULL, charon->name); if (address) { /* legacy configuration */ secret = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.secret", NULL); + "%s.plugins.eap-radius.secret", NULL, charon->name); if (!secret) { DBG1(DBG_CFG, "no RADUIS secret defined"); return; } nas_identifier = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.nas_identifier", "strongSwan"); + "%s.plugins.eap-radius.nas_identifier", "strongSwan", + charon->name); auth_port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.port", AUTH_PORT); + "%s.plugins.eap-radius.port", AUTH_PORT, charon->name); sockets = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.sockets", 1); + "%s.plugins.eap-radius.sockets", 1, charon->name); config = radius_config_create(address, address, auth_port, ACCT_PORT, nas_identifier, secret, sockets, 0); if (!config) @@ -118,38 +119,43 @@ static void load_configs(private_eap_radius_plugin_t *this) } enumerator = lib->settings->create_section_enumerator(lib->settings, - "charon.plugins.eap-radius.servers"); + "%s.plugins.eap-radius.servers", charon->name); while (enumerator->enumerate(enumerator, §ion)) { address = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.servers.%s.address", NULL, section); + "%s.plugins.eap-radius.servers.%s.address", NULL, + charon->name, section); if (!address) { DBG1(DBG_CFG, "RADIUS server '%s' misses address, skipped", section); continue; } secret = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.servers.%s.secret", NULL, section); + "%s.plugins.eap-radius.servers.%s.secret", NULL, + charon->name, section); if (!secret) { DBG1(DBG_CFG, "RADIUS server '%s' misses secret, skipped", section); continue; } nas_identifier = lib->settings->get_str(lib->settings, - "charon.plugins.eap-radius.servers.%s.nas_identifier", - "strongSwan", section); + "%s.plugins.eap-radius.servers.%s.nas_identifier", "strongSwan", + charon->name, section); auth_port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.auth_port", + "%s.plugins.eap-radius.servers.%s.auth_port", lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.port", - AUTH_PORT, section), - section); + "%s.plugins.eap-radius.servers.%s.port", + AUTH_PORT, charon->name, section), + charon->name, section); acct_port = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, section); + "%s.plugins.eap-radius.servers.%s.acct_port", ACCT_PORT, + charon->name, section); sockets = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.sockets", 1, section); + "%s.plugins.eap-radius.servers.%s.sockets", 1, + charon->name, section); preference = lib->settings->get_int(lib->settings, - "charon.plugins.eap-radius.servers.%s.preference", 0, section); + "%s.plugins.eap-radius.servers.%s.preference", 0, + charon->name, section); config = radius_config_create(section, address, auth_port, acct_port, nas_identifier, secret, sockets, preference); if (!config) @@ -242,12 +248,12 @@ plugin_t *eap_radius_plugin_create() instance = this; if (lib->settings->get_bool(lib->settings, - "charon.plugins.eap-radius.accounting", FALSE)) + "%s.plugins.eap-radius.accounting", FALSE, charon->name)) { charon->bus->add_listener(charon->bus, &this->accounting->listener); } if (lib->settings->get_bool(lib->settings, - "charon.plugins.eap-radius.dae.enable", FALSE)) + "%s.plugins.eap-radius.dae.enable", FALSE, charon->name)) { this->dae = eap_radius_dae_create(this->accounting); } diff --git a/src/libcharon/plugins/eap_sim/Makefile.in b/src/libcharon/plugins/eap_sim/Makefile.in index d06929522..99a5c1cc5 100644 --- a/src/libcharon/plugins/eap_sim/Makefile.in +++ b/src/libcharon/plugins/eap_sim/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_eap_sim_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_sim_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_sim_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.c b/src/libcharon/plugins/eap_sim/eap_sim_peer.c index 1d1ab99e0..ff96e9279 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_peer.c +++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.c @@ -105,14 +105,31 @@ struct private_eap_sim_peer_t { /* version of SIM protocol we speak */ static chunk_t version = chunk_from_chars(0x00,0x01); +/** + * Generate a payload from a message, destroy message + */ +static bool generate_payload(simaka_message_t *message, chunk_t data, + eap_payload_t **out) +{ + chunk_t chunk; + bool ok; + + ok = message->generate(message, data, &chunk); + if (ok) + { + *out = eap_payload_create_data_own(chunk); + } + message->destroy(message); + return ok; +} + /** * Create a SIM_CLIENT_ERROR */ -static eap_payload_t* create_client_error(private_eap_sim_peer_t *this, - simaka_client_error_t code) +static bool create_client_error(private_eap_sim_peer_t *this, + simaka_client_error_t code, eap_payload_t **out) { simaka_message_t *message; - eap_payload_t *out; u_int16_t encoded; DBG1(DBG_IKE, "sending client error '%N'", simaka_client_error_names, code); @@ -122,9 +139,7 @@ static eap_payload_t* create_client_error(private_eap_sim_peer_t *this, encoded = htons(code); message->add_attribute(message, AT_CLIENT_ERROR_CODE, chunk_create((char*)&encoded, sizeof(encoded))); - out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - return out; + return generate_payload(message, chunk_empty, out); } /** @@ -175,8 +190,11 @@ static status_t process_start(private_eap_sim_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); enumerator->destroy(enumerator); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -187,7 +205,10 @@ static status_t process_start(private_eap_sim_peer_t *this, if (!supported) { DBG1(DBG_IKE, "server does not support EAP-SIM version number 1"); - *out = create_client_error(this, SIM_UNSUPPORTED_VERSION); + if (!create_client_error(this, SIM_UNSUPPORTED_VERSION, out)) + { + return FAILED; + } return NEED_MORE; } @@ -221,7 +242,10 @@ static status_t process_start(private_eap_sim_peer_t *this, /* generate AT_NONCE_MT value */ rng = this->crypto->get_rng(this->crypto); free(this->nonce.ptr); - rng->allocate_bytes(rng, NONCE_LEN, &this->nonce); + if (!rng->allocate_bytes(rng, NONCE_LEN, &this->nonce)) + { + return FAILED; + } message = simaka_message_create(FALSE, this->identifier, EAP_SIM, SIM_START, this->crypto); @@ -234,9 +258,10 @@ static status_t process_start(private_eap_sim_peer_t *this, { message->add_attribute(message, AT_IDENTITY, id); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } return NEED_MORE; } @@ -270,8 +295,11 @@ static status_t process_challenge(private_eap_sim_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); enumerator->destroy(enumerator); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -285,7 +313,10 @@ static status_t process_challenge(private_eap_sim_peer_t *this, memeq(rands.ptr, rands.ptr + SIM_RAND_LEN, SIM_RAND_LEN)) { DBG1(DBG_IKE, "no valid AT_RAND received"); - *out = create_client_error(this, SIM_INSUFFICIENT_CHALLENGES); + if (!create_client_error(this, SIM_INSUFFICIENT_CHALLENGES, out)) + { + return FAILED; + } return NEED_MORE; } /* get two or three KCs/SRESes from SIM using RANDs */ @@ -297,7 +328,10 @@ static status_t process_challenge(private_eap_sim_peer_t *this, rands.ptr, sres.ptr, kc.ptr)) { DBG1(DBG_IKE, "unable to get EAP-SIM triplet"); - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } DBG3(DBG_IKE, "got triplet for RAND %b\n Kc %b\n SRES %b", @@ -313,16 +347,22 @@ static status_t process_challenge(private_eap_sim_peer_t *this, id = this->pseudonym; } data = chunk_cata("cccc", kcs, this->nonce, this->version_list, version); - free(this->msk.ptr); - this->msk = this->crypto->derive_keys_full(this->crypto, id, data, &mk); + chunk_clear(&this->msk); + if (!this->crypto->derive_keys_full(this->crypto, id, data, &mk, &this->msk)) + { + return FAILED; + } memcpy(this->mk, mk.ptr, mk.len); - free(mk.ptr); + chunk_clear(&mk); /* Verify AT_MAC attribute, signature is over "EAP packet | NONCE_MT", and * parse() again after key derivation, reading encrypted attributes */ if (!in->verify(in, this->nonce) || !in->parse(in)) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } @@ -352,8 +392,10 @@ static status_t process_challenge(private_eap_sim_peer_t *this, /* build response with AT_MAC, built over "EAP packet | n*SRES" */ message = simaka_message_create(FALSE, this->identifier, EAP_SIM, SIM_CHALLENGE, this->crypto); - *out = eap_payload_create_data_own(message->generate(message, sreses)); - message->destroy(message); + if (!generate_payload(message, sreses, out)) + { + return FAILED; + } return NEED_MORE; } @@ -384,17 +426,26 @@ static status_t process_reauthentication(private_eap_sim_peer_t *this, { DBG1(DBG_IKE, "received %N, but not expected", simaka_subtype_names, SIM_REAUTHENTICATION); - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } - this->crypto->derive_keys_reauth(this->crypto, - chunk_create(this->mk, HASH_SIZE_SHA1)); + if (!this->crypto->derive_keys_reauth(this->crypto, + chunk_create(this->mk, HASH_SIZE_SHA1))) + { + return FAILED; + } /* verify MAC and parse again with decryption key */ if (!in->verify(in, chunk_empty) || !in->parse(in)) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } @@ -415,8 +466,11 @@ static status_t process_reauthentication(private_eap_sim_peer_t *this, default: if (!simaka_attribute_skippable(type)) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); enumerator->destroy(enumerator); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } break; @@ -427,7 +481,10 @@ static status_t process_reauthentication(private_eap_sim_peer_t *this, if (!nonce.len || !counter.len) { DBG1(DBG_IKE, "EAP-SIM/Request/Re-Authentication message incomplete"); - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } @@ -440,10 +497,14 @@ static status_t process_reauthentication(private_eap_sim_peer_t *this, } else { - free(this->msk.ptr); - this->msk = this->crypto->derive_keys_reauth_msk(this->crypto, - this->reauth, counter, nonce, - chunk_create(this->mk, HASH_SIZE_SHA1)); + chunk_clear(&this->msk); + if (!this->crypto->derive_keys_reauth_msk(this->crypto, + this->reauth, counter, nonce, + chunk_create(this->mk, HASH_SIZE_SHA1), &this->msk)) + { + message->destroy(message); + return FAILED; + } if (id.len) { identification_t *reauth; @@ -455,8 +516,10 @@ static status_t process_reauthentication(private_eap_sim_peer_t *this, } } message->add_attribute(message, AT_COUNTER, counter); - *out = eap_payload_create_data_own(message->generate(message, nonce)); - message->destroy(message); + if (!generate_payload(message, nonce, out)) + { + return FAILED; + } return NEED_MORE; } @@ -506,13 +569,17 @@ static status_t process_notification(private_eap_sim_peer_t *this, { /* empty notification reply */ message = simaka_message_create(FALSE, this->identifier, EAP_SIM, SIM_NOTIFICATION, this->crypto); - *out = eap_payload_create_data_own(message->generate(message, - chunk_empty)); - message->destroy(message); + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } } else { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } } return NEED_MORE; } @@ -529,13 +596,19 @@ METHOD(eap_method_t, process, status_t, message = simaka_message_create_from_payload(in->get_data(in), this->crypto); if (!message) { - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } if (!message->parse(message)) { message->destroy(message); - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + return FAILED; + } return NEED_MORE; } switch (message->get_subtype(message)) @@ -555,8 +628,14 @@ METHOD(eap_method_t, process, status_t, default: DBG1(DBG_IKE, "unable to process EAP-SIM subtype %N", simaka_subtype_names, message->get_subtype(message)); - *out = create_client_error(this, SIM_UNABLE_TO_PROCESS); - status = NEED_MORE; + if (!create_client_error(this, SIM_UNABLE_TO_PROCESS, out)) + { + status = FAILED; + } + else + { + status = NEED_MORE; + } break; } message->destroy(message); diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.h b/src/libcharon/plugins/eap_sim/eap_sim_peer.h index ba72ce484..38315b75a 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_peer.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_PEER_H_ #define EAP_SIM_PEER_H_ -#include +#include typedef struct eap_sim_peer_t eap_sim_peer_t; diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.c b/src/libcharon/plugins/eap_sim/eap_sim_server.c index e0f7e92ad..334e2df1d 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_server.c +++ b/src/libcharon/plugins/eap_sim/eap_sim_server.c @@ -113,6 +113,24 @@ struct private_eap_sim_server_t { /* version of SIM protocol we speak */ static chunk_t version = chunk_from_chars(0x00,0x01); +/** + * Generate a payload from a message, destroy message + */ +static bool generate_payload(simaka_message_t *message, chunk_t data, + eap_payload_t **out) +{ + chunk_t chunk; + bool ok; + + ok = message->generate(message, data, &chunk); + if (ok) + { + *out = eap_payload_create_data_own(chunk); + } + message->destroy(message); + return ok; +} + METHOD(eap_method_t, initiate, status_t, private_eap_sim_server_t *this, eap_payload_t **out) { @@ -133,9 +151,10 @@ METHOD(eap_method_t, initiate, status_t, { message->add_attribute(message, AT_PERMANENT_ID_REQ, chunk_empty); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } this->pending = SIM_START; return NEED_MORE; } @@ -155,15 +174,21 @@ static status_t reauthenticate(private_eap_sim_server_t *this, DBG1(DBG_IKE, "initiating EAP-SIM reauthentication"); rng = this->crypto->get_rng(this->crypto); - rng->allocate_bytes(rng, NONCE_LEN, &this->nonce); + if (!rng->allocate_bytes(rng, NONCE_LEN, &this->nonce)) + { + return FAILED; + } mkc = chunk_create(mk, HASH_SIZE_SHA1); counter = htons(counter); this->counter = chunk_clone(chunk_create((char*)&counter, sizeof(counter))); - this->crypto->derive_keys_reauth(this->crypto, mkc); - this->msk = this->crypto->derive_keys_reauth_msk(this->crypto, - this->reauth, this->counter, this->nonce, mkc); + if (!this->crypto->derive_keys_reauth(this->crypto, mkc) || + !this->crypto->derive_keys_reauth_msk(this->crypto, + this->reauth, this->counter, this->nonce, mkc, &this->msk)) + { + return FAILED; + } message = simaka_message_create(TRUE, this->identifier++, EAP_SIM, SIM_REAUTHENTICATION, this->crypto); @@ -176,9 +201,10 @@ static status_t reauthenticate(private_eap_sim_server_t *this, next->get_encoding(next)); next->destroy(next); } - *out = eap_payload_create_data_own(message->generate(message, chunk_empty)); - message->destroy(message); - + if (!generate_payload(message, chunk_empty, out)) + { + return FAILED; + } this->pending = SIM_REAUTHENTICATION; return NEED_MORE; } @@ -386,13 +412,17 @@ static status_t process_start(private_eap_sim_server_t *this, { id = this->pseudonym; } - this->msk = this->crypto->derive_keys_full(this->crypto, id, data, &mk); + if (!this->crypto->derive_keys_full(this->crypto, id, data, &mk, &this->msk)) + { + return FAILED; + } /* build response with AT_MAC, built over "EAP packet | NONCE_MT" */ message = simaka_message_create(TRUE, this->identifier++, EAP_SIM, SIM_CHALLENGE, this->crypto); message->add_attribute(message, AT_RAND, rands); id = this->mgr->provider_gen_reauth(this->mgr, this->permanent, mk.ptr); + free(mk.ptr); if (id) { message->add_attribute(message, AT_NEXT_REAUTH_ID, @@ -406,10 +436,10 @@ static status_t process_start(private_eap_sim_server_t *this, id->get_encoding(id)); id->destroy(id); } - *out = eap_payload_create_data_own(message->generate(message, nonce)); - message->destroy(message); - - free(mk.ptr); + if (!generate_payload(message, nonce, out)) + { + return FAILED; + } this->pending = SIM_CHALLENGE; return NEED_MORE; } @@ -604,7 +634,8 @@ eap_sim_server_t *eap_sim_server_create(identification_t *server, this->permanent = peer->clone(peer); this->use_reauth = this->use_pseudonym = this->use_permanent = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-sim.request_identity", TRUE); + "%s.plugins.eap-sim.request_identity", TRUE, + charon->name); /* generate a non-zero identifier */ do { diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.h b/src/libcharon/plugins/eap_sim/eap_sim_server.h index c0ed64ff2..84408c43c 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_server.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_server.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_SERVER_H_ #define EAP_SIM_SERVER_H_ -#include +#include typedef struct eap_sim_server_t eap_sim_server_t; diff --git a/src/libcharon/plugins/eap_sim_file/Makefile.in b/src/libcharon/plugins/eap_sim_file/Makefile.in index bebf62e5b..d1caa30c4 100644 --- a/src/libcharon/plugins/eap_sim_file/Makefile.in +++ b/src/libcharon/plugins/eap_sim_file/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_eap_sim_file_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_sim_file_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_sim_file_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in index 5c05b2bf1..83d931883 100644 --- a/src/libcharon/plugins/eap_sim_pcsc/Makefile.in +++ b/src/libcharon/plugins/eap_sim_pcsc/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,7 +90,7 @@ libstrongswan_eap_sim_pcsc_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_sim_pcsc_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_sim_pcsc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -115,6 +116,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -209,11 +211,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -230,11 +235,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -250,6 +256,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -259,7 +266,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in index 0d7c32c14..e8436f2b6 100644 --- a/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_pseudonym/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,7 +90,7 @@ libstrongswan_eap_simaka_pseudonym_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_simaka_pseudonym_la_rpath = \ @MONOLITHIC_FALSE@ -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_simaka_pseudonym_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -115,6 +116,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -209,11 +211,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -230,11 +235,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -250,6 +256,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -259,7 +266,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_simaka_pseudonym/eap_simaka_pseudonym_provider.c b/src/libcharon/plugins/eap_simaka_pseudonym/eap_simaka_pseudonym_provider.c index 49c3ad328..3070b808a 100644 --- a/src/libcharon/plugins/eap_simaka_pseudonym/eap_simaka_pseudonym_provider.c +++ b/src/libcharon/plugins/eap_simaka_pseudonym/eap_simaka_pseudonym_provider.c @@ -15,6 +15,7 @@ #include "eap_simaka_pseudonym_provider.h" +#include #include typedef struct private_eap_simaka_pseudonym_provider_t private_eap_simaka_pseudonym_provider_t; @@ -82,7 +83,10 @@ static identification_t *gen_identity( { char buf[8], hex[sizeof(buf) * 2 + 1]; - this->rng->get_bytes(this->rng, sizeof(buf), buf); + if (!this->rng->get_bytes(this->rng, sizeof(buf), buf)) + { + return NULL; + } chunk_to_hex(chunk_create(buf, sizeof(buf)), hex, FALSE); return identification_create_from_string(hex); @@ -106,6 +110,11 @@ METHOD(simaka_provider_t, gen_pseudonym, identification_t*, } pseudonym = gen_identity(this); + if (!pseudonym) + { + DBG1(DBG_CFG, "failed to generate pseudonym"); + return NULL; + } /* create new entries */ id = id->clone(id); diff --git a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in index 6177f3b3a..627f8c12e 100644 --- a/src/libcharon/plugins/eap_simaka_reauth/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_reauth/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_eap_simaka_reauth_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_simaka_reauth_la_rpath = \ @MONOLITHIC_FALSE@ -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_simaka_reauth_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_simaka_reauth/eap_simaka_reauth_provider.c b/src/libcharon/plugins/eap_simaka_reauth/eap_simaka_reauth_provider.c index ba1a32778..b1a9a7f7c 100644 --- a/src/libcharon/plugins/eap_simaka_reauth/eap_simaka_reauth_provider.c +++ b/src/libcharon/plugins/eap_simaka_reauth/eap_simaka_reauth_provider.c @@ -81,7 +81,10 @@ static identification_t *gen_identity(private_eap_simaka_reauth_provider_t *this { char buf[8], hex[sizeof(buf) * 2 + 1]; - this->rng->get_bytes(this->rng, sizeof(buf), buf); + if (!this->rng->get_bytes(this->rng, sizeof(buf), buf)) + { + return NULL; + } chunk_to_hex(chunk_create(buf, sizeof(buf)), hex, FALSE); return identification_create_from_string(hex); @@ -116,7 +119,14 @@ METHOD(simaka_provider_t, gen_reauth, identification_t*, char mk[HASH_SIZE_SHA1]) { reauth_data_t *data; - identification_t *permanent; + identification_t *permanent, *new_id; + + new_id = gen_identity(this); + if (!new_id) + { + DBG1(DBG_CFG, "failed to generate identity"); + return NULL; + } data = this->reauth->get(this->reauth, id); if (data) @@ -125,14 +135,18 @@ METHOD(simaka_provider_t, gen_reauth, identification_t*, if (permanent) { data->id->destroy(data->id); - data->id = gen_identity(this); + data->id = new_id; this->permanent->put(this->permanent, data->id, permanent); } + else + { + new_id->destroy(new_id); + } } else { /* generate new entry */ INIT(data, - .id = gen_identity(this), + .id = new_id, ); id = id->clone(id); this->reauth->put(this->reauth, id, data); diff --git a/src/libcharon/plugins/eap_simaka_sql/Makefile.in b/src/libcharon/plugins/eap_simaka_sql/Makefile.in index 3639e24e8..8030190f8 100644 --- a/src/libcharon/plugins/eap_simaka_sql/Makefile.in +++ b/src/libcharon/plugins/eap_simaka_sql/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_eap_simaka_sql_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_simaka_sql_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_simaka_sql_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c index 6e590fae7..6bcc58e66 100644 --- a/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c +++ b/src/libcharon/plugins/eap_simaka_sql/eap_simaka_sql_plugin.c @@ -65,7 +65,8 @@ static bool load_db(private_eap_simaka_sql_t *this, char *uri; uri = lib->settings->get_str(lib->settings, - "charon.plugins.eap-simaka-sql.database", NULL); + "%s.plugins.eap-simaka-sql.database", NULL, + charon->name); if (!uri) { DBG1(DBG_CFG, "eap-simaka-sql database URI missing"); @@ -78,7 +79,8 @@ static bool load_db(private_eap_simaka_sql_t *this, return FALSE; } remove_used = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-simaka-sql.remove_used", FALSE); + "%s.plugins.eap-simaka-sql.remove_used", FALSE, + charon->name); this->provider = eap_simaka_sql_provider_create(this->db, remove_used); this->card = eap_simaka_sql_card_create(this->db, remove_used); diff --git a/src/libcharon/plugins/eap_tls/Makefile.in b/src/libcharon/plugins/eap_tls/Makefile.in index 67e2c0cb0..55e03b2f7 100644 --- a/src/libcharon/plugins/eap_tls/Makefile.in +++ b/src/libcharon/plugins/eap_tls/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_eap_tls_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_tls_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_tls_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_tls/eap_tls.c b/src/libcharon/plugins/eap_tls/eap_tls.c index dc0289ba2..48e38755d 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.c +++ b/src/libcharon/plugins/eap_tls/eap_tls.c @@ -144,11 +144,13 @@ static eap_tls_t *eap_tls_create(identification_t *server, ); frag_size = lib->settings->get_int(lib->settings, - "charon.plugins.eap-tls.fragment_size", MAX_FRAGMENT_LEN); + "%s.plugins.eap-tls.fragment_size", MAX_FRAGMENT_LEN, + charon->name); max_msg_count = lib->settings->get_int(lib->settings, - "charon.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT); + "%s.plugins.eap-tls.max_message_count", MAX_MESSAGE_COUNT, + charon->name); include_length = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-tls.include_length", TRUE); + "%s.plugins.eap-tls.include_length", TRUE, charon->name); tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TLS, NULL, NULL); this->tls_eap = tls_eap_create(EAP_TLS, tls, frag_size, max_msg_count, include_length); diff --git a/src/libcharon/plugins/eap_tls/eap_tls.h b/src/libcharon/plugins/eap_tls/eap_tls.h index 7e080230a..6779c3994 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.h +++ b/src/libcharon/plugins/eap_tls/eap_tls.h @@ -23,7 +23,7 @@ typedef struct eap_tls_t eap_tls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TLS. diff --git a/src/libcharon/plugins/eap_tnc/Makefile.in b/src/libcharon/plugins/eap_tnc/Makefile.in index 62278f835..c452f7e16 100644 --- a/src/libcharon/plugins/eap_tnc/Makefile.in +++ b/src/libcharon/plugins/eap_tnc/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_eap_tnc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_eap_tnc_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_tnc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.c b/src/libcharon/plugins/eap_tnc/eap_tnc.c index 33a83ba18..7efc0fec5 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.c +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -19,6 +19,17 @@ #include #include #include +#include + +/** + * Maximum size of an EAP-TNC message + */ +#define EAP_TNC_MAX_MESSAGE_LEN 65535 + +/** + * Maximum number of EAP-TNC messages allowed + */ +#define EAP_TNC_MAX_MESSAGE_COUNT 10 typedef struct private_eap_tnc_t private_eap_tnc_t; @@ -38,12 +49,6 @@ struct private_eap_tnc_t { tls_eap_t *tls_eap; }; - -/** Maximum number of EAP-TNC messages/fragments allowed */ -#define MAX_MESSAGE_COUNT 10 -/** Default size of a EAP-TNC fragment */ -#define MAX_FRAGMENT_LEN 50000 - METHOD(eap_method_t, initiate, status_t, private_eap_tnc_t *this, eap_payload_t **out) { @@ -124,9 +129,7 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, identification_t *peer, bool is_server) { private_eap_tnc_t *this; - size_t frag_size; int max_msg_count; - bool include_length; char* protocol; tnccs_type_t type; tnccs_t *tnccs; @@ -146,14 +149,11 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, }, ); - frag_size = lib->settings->get_int(lib->settings, - "charon.plugins.eap-tnc.fragment_size", MAX_FRAGMENT_LEN); max_msg_count = lib->settings->get_int(lib->settings, - "charon.plugins.eap-tnc.max_message_count", MAX_MESSAGE_COUNT); - include_length = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-tnc.include_length", TRUE); - protocol = lib->settings->get_str(lib->settings, - "charon.plugins.eap-tnc.protocol", "tnccs-1.1"); + "%s.plugins.eap-tnc.max_message_count", + EAP_TNC_MAX_MESSAGE_COUNT, charon->name); + protocol = lib->settings->get_str(lib->settings, + "%s.plugins.eap-tnc.protocol", "tnccs-1.1", charon->name); if (strcaseeq(protocol, "tnccs-2.0")) { type = TNCCS_2_0; @@ -173,8 +173,9 @@ static eap_tnc_t *eap_tnc_create(identification_t *server, return NULL; } tnccs = tnc->tnccs->create_instance(tnc->tnccs, type, is_server); - this->tls_eap = tls_eap_create(EAP_TNC, (tls_t*)tnccs, frag_size, - max_msg_count, include_length); + this->tls_eap = tls_eap_create(EAP_TNC, (tls_t*)tnccs, + EAP_TNC_MAX_MESSAGE_LEN, + max_msg_count, FALSE); if (!this->tls_eap) { free(this); diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.h b/src/libcharon/plugins/eap_tnc/eap_tnc.h index 7e166fb60..09abe60fc 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.h +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ typedef struct eap_tnc_t eap_tnc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-TNC. diff --git a/src/libcharon/plugins/eap_ttls/Makefile.in b/src/libcharon/plugins/eap_ttls/Makefile.in index b41fbd719..95a5c1fda 100644 --- a/src/libcharon/plugins/eap_ttls/Makefile.in +++ b/src/libcharon/plugins/eap_ttls/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_eap_ttls_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_eap_ttls_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_eap_ttls_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.c b/src/libcharon/plugins/eap_ttls/eap_ttls.c index ace62f6b9..ebd1c5479 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.c @@ -146,16 +146,19 @@ static eap_ttls_t *eap_ttls_create(identification_t *server, }, ); if (is_server && !lib->settings->get_bool(lib->settings, - "charon.plugins.eap-ttls.request_peer_auth", FALSE)) + "%s.plugins.eap-ttls.request_peer_auth", FALSE, + charon->name)) { peer = NULL; } frag_size = lib->settings->get_int(lib->settings, - "charon.plugins.eap-ttls.fragment_size", MAX_FRAGMENT_LEN); + "%s.plugins.eap-ttls.fragment_size", MAX_FRAGMENT_LEN, + charon->name); max_msg_count = lib->settings->get_int(lib->settings, - "charon.plugins.eap-ttls.max_message_count", MAX_MESSAGE_COUNT); + "%s.plugins.eap-ttls.max_message_count", MAX_MESSAGE_COUNT, + charon->name); include_length = lib->settings->get_bool(lib->settings, - "charon.plugins.eap-ttls.include_length", TRUE); + "%s.plugins.eap-ttls.include_length", TRUE, charon->name); tls = tls_create(is_server, server, peer, TLS_PURPOSE_EAP_TTLS, application, NULL); this->tls_eap = tls_eap_create(EAP_TTLS, tls, frag_size, max_msg_count, @@ -170,7 +173,7 @@ static eap_ttls_t *eap_ttls_create(identification_t *server, } eap_ttls_t *eap_ttls_create_server(identification_t *server, - identification_t *peer) + identification_t *peer) { return eap_ttls_create(server, peer, TRUE, &eap_ttls_server_create(server, peer)->application); diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.h b/src/libcharon/plugins/eap_ttls/eap_ttls.h index 6e3bf2ceb..84b1a2d19 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.h +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.h @@ -23,7 +23,7 @@ typedef struct eap_ttls_t eap_ttls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TTLS. diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index 4b6897b1d..00a4da3f8 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; @@ -138,7 +138,7 @@ METHOD(tls_application_t, process, status_t, chunk_free(&avp_data); } while (eap_pos < eap_data.len); - + in = eap_payload_create_data(eap_data); chunk_free(&eap_data); payload = (payload_t*)in; @@ -192,7 +192,8 @@ METHOD(tls_application_t, process, status_t, if (!this->method) { DBG1(DBG_IKE, "EAP method not supported"); - this->out = eap_payload_create_nak(in->get_identifier(in)); + this->out = eap_payload_create_nak(in->get_identifier(in), 0, 0, + in->is_expanded(in)); in->destroy(in); return NEED_MORE; } diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index 3c46993b7..1418d6a4d 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_eap_ttls_server_t private_eap_ttls_server_t; @@ -78,7 +78,8 @@ static status_t start_phase2_auth(private_eap_ttls_server_t *this) eap_type_t type; eap_type_str = lib->settings->get_str(lib->settings, - "charon.plugins.eap-ttls.phase2_method", "md5"); + "%s.plugins.eap-ttls.phase2_method", "md5", + charon->name); type = eap_type_from_string(eap_type_str); if (type == 0) { @@ -110,7 +111,7 @@ static status_t start_phase2_auth(private_eap_ttls_server_t *this) static status_t start_phase2_tnc(private_eap_ttls_server_t *this) { if (this->start_phase2_tnc && lib->settings->get_bool(lib->settings, - "charon.plugins.eap-ttls.phase2_tnc", FALSE)) + "%s.plugins.eap-ttls.phase2_tnc", FALSE, charon->name)) { DBG1(DBG_IKE, "phase2 method %N selected", eap_type_names, EAP_TNC); this->method = charon->eap->create_instance(charon->eap, EAP_TNC, @@ -168,7 +169,7 @@ METHOD(tls_application_t, process, status_t, code = in->get_code(in); received_type = in->get_type(in, &received_vendor); DBG1(DBG_IKE, "received tunneled EAP-TTLS AVP [EAP/%N/%N]", - eap_code_short_names, code, + eap_code_short_names, code, eap_type_short_names, received_type); if (code != EAP_RESPONSE) { @@ -234,7 +235,7 @@ METHOD(tls_application_t, process, status_t, /* Start Phase 2 of EAP-TTLS authentication */ if (lib->settings->get_bool(lib->settings, - "charon.plugins.eap-ttls.request_peer_auth", FALSE)) + "%s.plugins.eap-ttls.request_peer_auth", FALSE, charon->name)) { return start_phase2_tnc(this); } @@ -279,7 +280,7 @@ METHOD(tls_application_t, process, status_t, DBG1(DBG_IKE, "%N method failed", eap_type_names, type); } return FAILED; - } + } return status; } @@ -293,7 +294,7 @@ METHOD(tls_application_t, build, status_t, if (this->method == NULL && this->start_phase2 && lib->settings->get_bool(lib->settings, - "charon.plugins.eap-ttls.phase2_piggyback", FALSE)) + "%s.plugins.eap-ttls.phase2_piggyback", FALSE, charon->name)) { /* generate an EAP Identity request which will be piggybacked right * onto the TLS Finished message thus initiating EAP-TTLS phase2 diff --git a/src/libcharon/plugins/farp/Makefile.in b/src/libcharon/plugins/farp/Makefile.in index cfb51933c..c26bd7856 100644 --- a/src/libcharon/plugins/farp/Makefile.in +++ b/src/libcharon/plugins/farp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_farp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_farp_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_farp_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_farp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/farp/farp_spoofer.c b/src/libcharon/plugins/farp/farp_spoofer.c index 587a3a74e..52b037c19 100644 --- a/src/libcharon/plugins/farp/farp_spoofer.c +++ b/src/libcharon/plugins/farp/farp_spoofer.c @@ -44,11 +44,6 @@ struct private_farp_spoofer_t { */ farp_listener_t *listener; - /** - * Callback job to read ARP requests - */ - callback_job_t *job; - /** * RAW socket for ARP requests */ @@ -135,7 +130,6 @@ static job_requeue_t receive_arp(private_farp_spoofer_t *this) METHOD(farp_spoofer_t, destroy, void, private_farp_spoofer_t *this) { - this->job->cancel(this->job); close(this->skt); free(this); } @@ -189,9 +183,9 @@ farp_spoofer_t *farp_spoofer_create(farp_listener_t *listener) return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_arp, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive_arp, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in index c66a550cd..0ac139ca0 100644 --- a/src/libcharon/plugins/ha/Makefile.in +++ b/src/libcharon/plugins/ha/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_ha_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_ha_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_ha_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_ha_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c index b08abe1a9..ae6296462 100644 --- a/src/libcharon/plugins/ha/ha_attribute.c +++ b/src/libcharon/plugins/ha/ha_attribute.c @@ -170,17 +170,29 @@ static bool responsible_for(private_ha_attribute_t *this, int bit) } METHOD(attribute_provider_t, acquire_address, host_t*, - private_ha_attribute_t *this, char *name, identification_t *id, + private_ha_attribute_t *this, linked_list_t *pools, identification_t *id, host_t *requested) { + enumerator_t *enumerator; pool_t *pool; int offset = -1, byte, bit; host_t *address; + char *name; + enumerator = pools->create_enumerator(pools); this->mutex->lock(this->mutex); - pool = get_pool(this, name); - if (pool) + while (enumerator->enumerate(enumerator, &name)) { + pool = get_pool(this, name); + if (!pool) + { + continue; + } + if (pool->base->get_family(pool->base) != + requested->get_family(requested)) + { + continue; + } for (byte = 0; byte < pool->size / 8; byte++) { if (pool->mask[byte] != 0xFF) @@ -208,6 +220,8 @@ METHOD(attribute_provider_t, acquire_address, host_t*, } } this->mutex->unlock(this->mutex); + enumerator->destroy(enumerator); + if (offset != -1) { address = offset2host(pool, offset); @@ -218,26 +232,40 @@ METHOD(attribute_provider_t, acquire_address, host_t*, } METHOD(attribute_provider_t, release_address, bool, - private_ha_attribute_t *this, char *name, host_t *address, + private_ha_attribute_t *this, linked_list_t *pools, host_t *address, identification_t *id) { + enumerator_t *enumerator; pool_t *pool; int offset; + char *name; bool found = FALSE; + enumerator = pools->create_enumerator(pools); this->mutex->lock(this->mutex); - pool = get_pool(this, name); - if (pool) + while (enumerator->enumerate(enumerator, &name)) { + pool = get_pool(this, name); + if (!pool) + { + continue; + } + if (pool->base->get_family(pool->base) != address->get_family(address)) + { + continue; + } offset = host2offset(pool, address); if (offset > 0 && offset < pool->size) { pool->mask[offset / 8] &= ~(1 << (offset % 8)); DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name); found = TRUE; + break; } } this->mutex->unlock(this->mutex); + enumerator->destroy(enumerator); + return found; } @@ -281,7 +309,7 @@ static void load_pools(private_ha_attribute_t *this) pool_t *pool; enumerator = lib->settings->create_key_value_enumerator(lib->settings, - "charon.plugins.ha.pools"); + "%s.plugins.ha.pools", charon->name); while (enumerator->enumerate(enumerator, &name, &net)) { net = strdup(net); diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c index 970a8a2b9..e21b461a7 100644 --- a/src/libcharon/plugins/ha/ha_cache.c +++ b/src/libcharon/plugins/ha/ha_cache.c @@ -88,6 +88,8 @@ typedef struct { ha_message_t *midi; /* last responder mid */ ha_message_t *midr; + /* last IV update */ + ha_message_t *iv; } entry_t; /** @@ -114,6 +116,7 @@ static void entry_destroy(entry_t *entry) entry->add->destroy(entry->add); DESTROY_IF(entry->midi); DESTROY_IF(entry->midr); + DESTROY_IF(entry->iv); free(entry); } @@ -164,6 +167,16 @@ METHOD(ha_cache_t, cache, void, } message->destroy(message); break; + case HA_IKE_IV: + entry = this->cache->get(this->cache, ike_sa); + if (entry) + { + DESTROY_IF(entry->iv); + entry->iv = message; + break; + } + message->destroy(message); + break; case HA_IKE_DELETE: entry = this->cache->remove(this->cache, ike_sa); if (entry) @@ -212,7 +225,8 @@ static status_t rekey_children(ike_sa_t *ike_sa) DBG1(DBG_CFG, "resyncing CHILD_SA using a delete"); status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); + child_sa->get_spi(child_sa, TRUE), + FALSE); } else { @@ -308,6 +322,10 @@ METHOD(ha_cache_t, resync, void, { this->socket->push(this->socket, entry->midr); } + if (entry->iv) + { + this->socket->push(this->socket, entry->iv); + } } } enumerator->destroy(enumerator); diff --git a/src/libcharon/plugins/ha/ha_ctl.c b/src/libcharon/plugins/ha/ha_ctl.c index 9c99807ed..cb9af3aed 100644 --- a/src/libcharon/plugins/ha/ha_ctl.c +++ b/src/libcharon/plugins/ha/ha_ctl.c @@ -48,11 +48,6 @@ struct private_ha_ctl_t { * Resynchronization message cache */ ha_cache_t *cache; - - /** - * FIFO reader thread - */ - callback_job_t *job; }; /** @@ -105,7 +100,6 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this) METHOD(ha_ctl_t, destroy, void, private_ha_ctl_t *this) { - this->job->cancel(this->job); free(this); } @@ -135,15 +129,16 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache) } umask(old); } - if (chown(HA_FIFO, charon->uid, charon->gid) != 0) + if (chown(HA_FIFO, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing HA FIFO permissions failed: %s", strerror(errno)); } - this->job = callback_job_create_with_prio((callback_job_cb_t)dispatch_fifo, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch_fifo, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 994f91d20..97ed13111 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -16,9 +16,13 @@ #include "ha_dispatcher.h" #include +#include +#include #include +#include typedef struct private_ha_dispatcher_t private_ha_dispatcher_t; +typedef struct ha_diffie_hellman_t ha_diffie_hellman_t; /** * Private data of an ha_dispatcher_t object. @@ -54,20 +58,66 @@ struct private_ha_dispatcher_t { * HA enabled pool */ ha_attribute_t *attr; +}; + +/** + * DH implementation for HA synced DH values + */ +struct ha_diffie_hellman_t { + + /** + * Implements diffie_hellman_t + */ + diffie_hellman_t dh; /** - * Dispatcher job + * Shared secret */ - callback_job_t *job; + chunk_t secret; + + /** + * Own public value + */ + chunk_t pub; }; +METHOD(diffie_hellman_t, dh_get_shared_secret, status_t, + ha_diffie_hellman_t *this, chunk_t *secret) +{ + *secret = chunk_clone(this->secret); + return SUCCESS; +} + +METHOD(diffie_hellman_t, dh_get_my_public_value, void, + ha_diffie_hellman_t *this, chunk_t *value) +{ + *value = chunk_clone(this->pub); +} + +METHOD(diffie_hellman_t, dh_destroy, void, + ha_diffie_hellman_t *this) +{ + free(this); +} + /** - * Quick and dirty hack implementation of diffie_hellman_t.get_shared_secret + * Create a HA synced DH implementation */ -static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret) +static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub) { - *secret = chunk_clone((*(chunk_t*)this->destroy)); - return SUCCESS; + ha_diffie_hellman_t *this; + + INIT(this, + .dh = { + .get_shared_secret = _dh_get_shared_secret, + .get_my_public_value = _dh_get_my_public_value, + .destroy = _dh_destroy, + }, + .secret = secret, + .pub = pub, + ); + + return &this->dh; } /** @@ -79,9 +129,12 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message ha_message_value_t value; enumerator_t *enumerator; ike_sa_t *ike_sa = NULL, *old_sa = NULL; + ike_version_t version = IKEV2; u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED; chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty; chunk_t secret = chunk_empty, old_skd = chunk_empty; + chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty; + bool ok = FALSE; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -89,12 +142,16 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message switch (attribute) { case HA_IKE_ID: - ike_sa = ike_sa_create(value.ike_sa_id); + ike_sa = ike_sa_create(value.ike_sa_id, + value.ike_sa_id->is_initiator(value.ike_sa_id), version); break; case HA_IKE_REKEY_ID: old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, value.ike_sa_id); break; + case HA_IKE_VERSION: + version = value.u8; + break; case HA_NONCE_I: nonce_i = value.chunk; break; @@ -104,6 +161,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message case HA_SECRET: secret = value.chunk; break; + case HA_LOCAL_DH: + dh_local = value.chunk; + break; + case HA_REMOTE_DH: + dh_remote = value.chunk; + break; + case HA_PSK: + psk = value.chunk; + break; case HA_OLD_SKD: old_skd = value.chunk; break; @@ -131,13 +197,9 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message if (ike_sa) { proposal_t *proposal; - keymat_t *keymat; - /* quick and dirty hack of a DH implementation ;-) */ - diffie_hellman_t dh = { .get_shared_secret = get_shared_secret, - .destroy = (void*)&secret }; + diffie_hellman_t *dh; proposal = proposal_create(PROTO_IKE, 0); - keymat = ike_sa->get_keymat(ike_sa); if (integ) { proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0); @@ -151,8 +213,35 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0); } charon->bus->set_sa(charon->bus, ike_sa); - if (keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r, - ike_sa->get_id(ike_sa), old_prf, old_skd)) + dh = ha_diffie_hellman_create(secret, dh_local); + if (ike_sa->get_version(ike_sa) == IKEV2) + { + keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + + ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i, + nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd); + } + if (ike_sa->get_version(ike_sa) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + shared_key_t *shared = NULL; + auth_method_t method = AUTH_RSA; + + if (psk.len) + { + method = AUTH_PSK; + shared = shared_key_create(SHARED_IKE, chunk_clone(psk)); + } + if (keymat_v1->create_hasher(keymat_v1, proposal)) + { + ok = keymat_v1->derive_ike_keys(keymat_v1, proposal, + dh, dh_remote, nonce_i, nonce_r, + ike_sa->get_id(ike_sa), method, shared); + } + DESTROY_IF(shared); + } + dh->destroy(dh); + if (ok) { if (old_sa) { @@ -168,6 +257,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message old_sa = NULL; } ike_sa->set_state(ike_sa, IKE_CONNECTING); + ike_sa->set_proposal(ike_sa, proposal); this->cache->cache(this->cache, ike_sa, message); message = NULL; charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); @@ -220,7 +310,7 @@ static void process_ike_update(private_ha_dispatcher_t *this, ike_sa_t *ike_sa = NULL; peer_cfg_t *peer_cfg = NULL; auth_cfg_t *auth; - bool received_vip = FALSE, first_peer_addr = TRUE; + bool received_vip = FALSE, first_local_vip = TRUE, first_peer_addr = TRUE; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -254,10 +344,19 @@ static void process_ike_update(private_ha_dispatcher_t *this, ike_sa->set_other_host(ike_sa, value.host->clone(value.host)); break; case HA_LOCAL_VIP: - ike_sa->set_virtual_ip(ike_sa, TRUE, value.host); + if (first_local_vip) + { + ike_sa->clear_virtual_ips(ike_sa, TRUE); + first_local_vip = FALSE; + } + ike_sa->add_virtual_ip(ike_sa, TRUE, value.host); break; case HA_REMOTE_VIP: - ike_sa->set_virtual_ip(ike_sa, FALSE, value.host); + if (!received_vip) + { + ike_sa->clear_virtual_ips(ike_sa, FALSE); + } + ike_sa->add_virtual_ip(ike_sa, FALSE, value.host); received_vip = TRUE; break; case HA_PEER_ADDR: @@ -289,6 +388,8 @@ static void process_ike_update(private_ha_dispatcher_t *this, set_extension(ike_sa, value.u32, EXT_STRONGSWAN); set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION); set_extension(ike_sa, value.u32, EXT_MS_WINDOWS); + set_extension(ike_sa, value.u32, EXT_XAUTH); + set_extension(ike_sa, value.u32, EXT_DPD); break; case HA_CONDITIONS: set_condition(ike_sa, value.u32, COND_NAT_ANY); @@ -299,6 +400,8 @@ static void process_ike_update(private_ha_dispatcher_t *this, set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN); set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR); set_condition(ike_sa, value.u32, COND_STALE); + set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN); + set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED); break; default: break; @@ -319,20 +422,31 @@ static void process_ike_update(private_ha_dispatcher_t *this, } if (received_vip) { + enumerator_t *pools, *vips; host_t *vip; char *pool; peer_cfg = ike_sa->get_peer_cfg(ike_sa); - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (peer_cfg && vip) + if (peer_cfg) { - pool = peer_cfg->get_pool(peer_cfg); - if (pool) + pools = peer_cfg->create_pool_enumerator(peer_cfg); + while (pools->enumerate(pools, &pool)) { - this->attr->reserve(this->attr, pool, vip); + vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (vips->enumerate(vips, &vip)) + { + this->attr->reserve(this->attr, pool, vip); + } + vips->destroy(vips); } + pools->destroy(pools); } } + if (ike_sa->get_version(ike_sa) == IKEV1) + { + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create(ike_sa->get_id(ike_sa))); + } this->cache->cache(this->cache, ike_sa, message); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } @@ -388,6 +502,59 @@ static void process_ike_mid(private_ha_dispatcher_t *this, } } +/** + * Process messages of type IKE_IV + */ +static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message) +{ + ha_message_attribute_t attribute; + ha_message_value_t value; + enumerator_t *enumerator; + ike_sa_t *ike_sa = NULL; + chunk_t iv = chunk_empty; + + enumerator = message->create_attribute_enumerator(message); + while (enumerator->enumerate(enumerator, &attribute, &value)) + { + switch (attribute) + { + case HA_IKE_ID: + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + value.ike_sa_id); + break; + case HA_IV: + iv = value.chunk; + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (ike_sa) + { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + if (iv.len) + { + keymat_v1_t *keymat; + + keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + if (keymat->update_iv(keymat, 0, iv)) + { + keymat->confirm_iv(keymat, 0); + } + } + } + this->cache->cache(this->cache, ike_sa, message); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + message->destroy(message); + } +} + /** * Process messages of type IKE_DELETE */ @@ -465,8 +632,7 @@ static void process_child_add(private_ha_dispatcher_t *this, child_cfg_t *config = NULL; child_sa_t *child_sa; proposal_t *proposal; - keymat_t *keymat; - bool initiator = FALSE, failed = FALSE; + bool initiator = FALSE, failed = FALSE, ok = FALSE; u_int32_t inbound_spi = 0, outbound_spi = 0; u_int16_t inbound_cpi = 0, outbound_cpi = 0; u_int8_t mode = MODE_TUNNEL, ipcomp = 0; @@ -476,9 +642,7 @@ static void process_child_add(private_ha_dispatcher_t *this, chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty; chunk_t encr_i, integ_i, encr_r, integ_r; linked_list_t *local_ts, *remote_ts; - /* quick and dirty hack of a DH implementation */ - diffie_hellman_t dh = { .get_shared_secret = get_shared_secret, - .destroy = (void*)&secret }; + diffie_hellman_t *dh = NULL; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -572,10 +736,30 @@ static void process_child_add(private_ha_dispatcher_t *this, proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len); } proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0); - keymat = ike_sa->get_keymat(ike_sa); + if (secret.len) + { + dh = ha_diffie_hellman_create(secret, chunk_empty); + } + if (ike_sa->get_version(ike_sa) == IKEV2) + { + keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); - if (!keymat->derive_child_keys(keymat, proposal, secret.ptr ? &dh : NULL, - nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) + ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh, + nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r); + } + if (ike_sa->get_version(ike_sa) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + u_int32_t spi_i, spi_r; + + spi_i = initiator ? inbound_spi : outbound_spi; + spi_r = initiator ? outbound_spi : inbound_spi; + + ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r, + nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r); + } + DESTROY_IF(dh); + if (!ok) { DBG1(DBG_CHD, "HA CHILD_SA key derivation failed"); child_sa->destroy(child_sa); @@ -825,6 +1009,9 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this) case HA_IKE_MID_RESPONDER: process_ike_mid(this, message, FALSE); break; + case HA_IKE_IV: + process_ike_iv(this, message); + break; case HA_IKE_DELETE: process_ike_delete(this, message); break; @@ -857,7 +1044,6 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this) METHOD(ha_dispatcher_t, destroy, void, private_ha_dispatcher_t *this) { - this->job->cancel(this->job); free(this); } @@ -881,9 +1067,9 @@ ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket, .kernel = kernel, .attr = attr, ); - this->job = callback_job_create_with_prio((callback_job_cb_t)dispatch, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index e818aec9c..442a3a23d 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -15,6 +15,9 @@ #include "ha_ike.h" +#include +#include + typedef struct private_ha_ike_t private_ha_ike_t; /** @@ -69,7 +72,8 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext) METHOD(listener_t, ike_keys, bool, private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey) + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey, + shared_key_t *shared) { ha_message_t *m; chunk_t secret; @@ -86,14 +90,15 @@ METHOD(listener_t, ike_keys, bool, } m = ha_message_create(HA_IKE_ADD); + m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa)); m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - if (rekey) + if (rekey && rekey->get_version(rekey) == IKEV2) { chunk_t skd; - keymat_t *keymat; + keymat_v2_t *keymat; - keymat = rekey->get_keymat(rekey); + keymat = (keymat_v2_t*)rekey->get_keymat(rekey); m->add_attribute(m, HA_IKE_REKEY_ID, rekey->get_id(rekey)); m->add_attribute(m, HA_ALG_OLD_PRF, keymat->get_skd(keymat, &skd)); m->add_attribute(m, HA_OLD_SKD, skd); @@ -120,6 +125,17 @@ METHOD(listener_t, ike_keys, bool, m->add_attribute(m, HA_NONCE_R, nonce_r); m->add_attribute(m, HA_SECRET, secret); chunk_clear(&secret); + if (ike_sa->get_version(ike_sa) == IKEV1) + { + dh->get_my_public_value(dh, &secret); + m->add_attribute(m, HA_LOCAL_DH, secret); + chunk_free(&secret); + m->add_attribute(m, HA_REMOTE_DH, dh_other); + if (shared) + { + m->add_attribute(m, HA_PSK, shared->get_key(shared)); + } + } this->socket->push(this->socket, m); this->cache->cache(this->cache, ike_sa, m); @@ -159,7 +175,9 @@ METHOD(listener_t, ike_updown, bool, | copy_condition(ike_sa, COND_EAP_AUTHENTICATED) | copy_condition(ike_sa, COND_CERTREQ_SEEN) | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR) - | copy_condition(ike_sa, COND_STALE); + | copy_condition(ike_sa, COND_STALE) + | copy_condition(ike_sa, COND_INIT_CONTACT_SEEN) + | copy_condition(ike_sa, COND_XAUTH_AUTHENTICATED); extension = copy_extension(ike_sa, EXT_NATT) | copy_extension(ike_sa, EXT_MOBIKE) @@ -167,7 +185,9 @@ METHOD(listener_t, ike_updown, bool, | copy_extension(ike_sa, EXT_MULTIPLE_AUTH) | copy_extension(ike_sa, EXT_STRONGSWAN) | copy_extension(ike_sa, EXT_EAP_ONLY_AUTHENTICATION) - | copy_extension(ike_sa, EXT_MS_WINDOWS); + | copy_extension(ike_sa, EXT_MS_WINDOWS) + | copy_extension(ike_sa, EXT_XAUTH) + | copy_extension(ike_sa, EXT_DPD); id = ike_sa->get_id(ike_sa); @@ -221,49 +241,125 @@ METHOD(listener_t, ike_state_change, bool, return TRUE; } +/** + * Send a virtual IP sync message for remote VIPs + */ +static void sync_vips(private_ha_ike_t *this, ike_sa_t *ike_sa) +{ + ha_message_t *m = NULL; + enumerator_t *enumerator; + host_t *vip; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (enumerator->enumerate(enumerator, &vip)) + { + if (!m) + { + m = ha_message_create(HA_IKE_UPDATE); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + } + m->add_attribute(m, HA_REMOTE_VIP, vip); + } + enumerator->destroy(enumerator); + + if (m) + { + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } +} + METHOD(listener_t, message_hook, bool, - private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming) + private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, + bool incoming, bool plain) { if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa)) { /* do not sync SA between nodes */ return TRUE; } - if (message->get_exchange_type(message) != IKE_SA_INIT && - message->get_request(message)) - { /* we sync on requests, but skip it on IKE_SA_INIT */ + if (plain && ike_sa->get_version(ike_sa) == IKEV2) + { + if (message->get_exchange_type(message) != IKE_SA_INIT && + message->get_request(message)) + { /* we sync on requests, but skip it on IKE_SA_INIT */ + ha_message_t *m; + + if (incoming) + { + m = ha_message_create(HA_IKE_MID_RESPONDER); + } + else + { + m = ha_message_create(HA_IKE_MID_INITIATOR); + } + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_MID, message->get_message_id(message) + 1); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + message->get_exchange_type(message) == IKE_AUTH && + !message->get_request(message)) + { /* After IKE_SA has been established, sync peers virtual IP. + * We cannot sync it in the state_change hook, it is installed later. + * TODO: where to sync local VIP? */ + sync_vips(this, ike_sa); + } + } + if (!plain && ike_sa->get_version(ike_sa) == IKEV1) + { ha_message_t *m; + keymat_v1_t *keymat; + u_int32_t mid; + chunk_t iv; - if (incoming) + mid = message->get_message_id(message); + if (mid == 0) { - m = ha_message_create(HA_IKE_MID_RESPONDER); + keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + if (keymat->get_iv(keymat, mid, &iv)) + { + m = ha_message_create(HA_IKE_IV); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_IV, iv); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } } - else + if (!incoming && message->get_exchange_type(message) == TRANSACTION) { - m = ha_message_create(HA_IKE_MID_INITIATOR); + sync_vips(this, ike_sa); } - m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_MID, message->get_message_id(message) + 1); - this->socket->push(this->socket, m); - this->cache->cache(this->cache, ike_sa, m); } - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && - message->get_exchange_type(message) == IKE_AUTH && - !message->get_request(message)) - { /* After IKE_SA has been established, sync peers virtual IP. - * We cannot sync it in the state_change hook, it is installed later. - * TODO: where to sync local VIP? */ + if (plain && ike_sa->get_version(ike_sa) == IKEV1 && + message->get_exchange_type(message) == INFORMATIONAL_V1) + { ha_message_t *m; - host_t *vip; + notify_payload_t *notify; + chunk_t data; + u_int32_t seq; - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip) + notify = message->get_notify(message, DPD_R_U_THERE); + if (notify) { - m = ha_message_create(HA_IKE_UPDATE); - m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_REMOTE_VIP, vip); - this->socket->push(this->socket, m); - this->cache->cache(this->cache, ike_sa, m); + data = notify->get_notification_data(notify); + if (data.len == 4) + { + seq = untoh32(data.ptr); + if (incoming) + { + m = ha_message_create(HA_IKE_MID_RESPONDER); + } + else + { + m = ha_message_create(HA_IKE_MID_INITIATOR); + } + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_MID, seq + 1); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } } } return TRUE; diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c index 2377a2630..c45339690 100644 --- a/src/libcharon/plugins/ha/ha_kernel.c +++ b/src/libcharon/plugins/ha/ha_kernel.c @@ -316,7 +316,8 @@ static void disable_all(private_ha_kernel_t *this) { while (enumerator->enumerate(enumerator, NULL, &file, NULL)) { - if (chown(file, charon->uid, charon->gid) != 0) + if (chown(file, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c index 810109a5d..6b00ed83f 100644 --- a/src/libcharon/plugins/ha/ha_message.c +++ b/src/libcharon/plugins/ha/ha_message.c @@ -46,7 +46,7 @@ struct private_ha_message_t { chunk_t buf; }; -ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC, +ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV, "IKE_ADD", "IKE_UPDATE", "IKE_MID_INITIATOR", @@ -58,6 +58,7 @@ ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC, "SEGMENT_TAKE", "STATUS", "RESYNC", + "IKE_IV", ); typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t; @@ -66,6 +67,7 @@ typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t; * Encoding if an ike_sa_id_t */ struct ike_sa_id_encoding_t { + u_int8_t ike_version; u_int64_t initiator_spi; u_int64_t responder_spi; u_int8_t initiator; @@ -156,6 +158,7 @@ METHOD(ha_message_t, add_attribute, void, enc = (ike_sa_id_encoding_t*)(this->buf.ptr + this->buf.len); this->buf.len += sizeof(ike_sa_id_encoding_t); enc->initiator = id->is_initiator(id); + enc->ike_version = id->get_ike_version(id); enc->initiator_spi = id->get_initiator_spi(id); enc->responder_spi = id->get_responder_spi(id); break; @@ -213,6 +216,7 @@ METHOD(ha_message_t, add_attribute, void, break; } /* u_int8_t */ + case HA_IKE_VERSION: case HA_INITIATOR: case HA_IPSEC_MODE: case HA_IPCOMP: @@ -263,6 +267,10 @@ METHOD(ha_message_t, add_attribute, void, case HA_NONCE_I: case HA_NONCE_R: case HA_SECRET: + case HA_LOCAL_DH: + case HA_REMOTE_DH: + case HA_PSK: + case HA_IV: case HA_OLD_SKD: { chunk_t chunk; @@ -351,8 +359,9 @@ METHOD(enumerator_t, attribute_enumerate, bool, return FALSE; } enc = (ike_sa_id_encoding_t*)(this->buf.ptr); - value->ike_sa_id = ike_sa_id_create(enc->initiator_spi, - enc->responder_spi, enc->initiator); + value->ike_sa_id = ike_sa_id_create(enc->ike_version, + enc->initiator_spi, enc->responder_spi, + enc->initiator); *attr_out = attr; this->cleanup = (void*)value->ike_sa_id->destroy; this->cleanup_data = value->ike_sa_id; @@ -426,6 +435,7 @@ METHOD(enumerator_t, attribute_enumerate, bool, return TRUE; } /* u_int8_t */ + case HA_IKE_VERSION: case HA_INITIATOR: case HA_IPSEC_MODE: case HA_IPCOMP: @@ -479,6 +489,10 @@ METHOD(enumerator_t, attribute_enumerate, bool, case HA_NONCE_I: case HA_NONCE_R: case HA_SECRET: + case HA_LOCAL_DH: + case HA_REMOTE_DH: + case HA_PSK: + case HA_IV: case HA_OLD_SKD: { size_t len; diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h index d0323d7a0..8cd30f711 100644 --- a/src/libcharon/plugins/ha/ha_message.h +++ b/src/libcharon/plugins/ha/ha_message.h @@ -30,7 +30,7 @@ /** * Protocol version of this implementation */ -#define HA_MESSAGE_VERSION 2 +#define HA_MESSAGE_VERSION 3 typedef struct ha_message_t ha_message_t; typedef enum ha_message_type_t ha_message_type_t; @@ -63,6 +63,8 @@ enum ha_message_type_t { HA_STATUS, /** segments the receiving node is requested to resync */ HA_RESYNC, + /** IV synchronization for IKEv1 Main/Aggressive mode */ + HA_IKE_IV, }; /** @@ -76,7 +78,7 @@ extern enum_name_t *ha_message_type_names; enum ha_message_attribute_t { /** ike_sa_id_t*, to identify IKE_SA */ HA_IKE_ID = 1, - /** ike_Sa_id_t*, identifies IKE_SA which gets rekeyed */ + /** ike_sa_id_t*, identifies IKE_SA which gets rekeyed */ HA_IKE_REKEY_ID, /** identification_t*, local identity */ HA_LOCAL_ID, @@ -142,6 +144,16 @@ enum ha_message_attribute_t { HA_SEGMENT, /** u_int16_t, Extended Sequence numbers */ HA_ESN, + /** u_int8_t, IKE version */ + HA_IKE_VERSION, + /** chunk_t, own DH public value */ + HA_LOCAL_DH, + /** chunk_t, remote DH public value */ + HA_REMOTE_DH, + /** chunk_t, shared secret for IKEv1 key derivation */ + HA_PSK, + /** chunk_t, IV for next IKEv1 message */ + HA_IV, }; /** diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c index b4bde5ea5..255eeafc0 100644 --- a/src/libcharon/plugins/ha/ha_plugin.c +++ b/src/libcharon/plugins/ha/ha_plugin.c @@ -128,19 +128,19 @@ plugin_t *ha_plugin_create() bool fifo, monitor, resync; local = lib->settings->get_str(lib->settings, - "charon.plugins.ha.local", NULL); + "%s.plugins.ha.local", NULL, charon->name); remote = lib->settings->get_str(lib->settings, - "charon.plugins.ha.remote", NULL); + "%s.plugins.ha.remote", NULL, charon->name); secret = lib->settings->get_str(lib->settings, - "charon.plugins.ha.secret", NULL); + "%s.plugins.ha.secret", NULL, charon->name); fifo = lib->settings->get_bool(lib->settings, - "charon.plugins.ha.fifo_interface", TRUE); + "%s.plugins.ha.fifo_interface", TRUE, charon->name); monitor = lib->settings->get_bool(lib->settings, - "charon.plugins.ha.monitor", TRUE); + "%s.plugins.ha.monitor", TRUE, charon->name); resync = lib->settings->get_bool(lib->settings, - "charon.plugins.ha.resync", TRUE); + "%s.plugins.ha.resync", TRUE, charon->name); count = min(SEGMENTS_MAX, lib->settings->get_int(lib->settings, - "charon.plugins.ha.segment_count", 1)); + "%s.plugins.ha.segment_count", 1, charon->name)); if (!local || !remote) { DBG1(DBG_CFG, "HA config misses local/remote address"); diff --git a/src/libcharon/plugins/ha/ha_segments.c b/src/libcharon/plugins/ha/ha_segments.c index c5a180683..fb07809ef 100644 --- a/src/libcharon/plugins/ha/ha_segments.c +++ b/src/libcharon/plugins/ha/ha_segments.c @@ -61,11 +61,6 @@ struct private_ha_segments_t { */ condvar_t *condvar; - /** - * Job checking for heartbeats - */ - callback_job_t *job; - /** * Total number of ClusterIP segments */ @@ -81,6 +76,11 @@ struct private_ha_segments_t { */ u_int node; + /** + * Are we checking for heartbeats? + */ + bool heartbeat_active; + /** * Interval we send hearbeats */ @@ -237,7 +237,7 @@ METHOD(listener_t, alert_hook, bool, { if (alert == ALERT_SHUTDOWN_SIGNAL) { - if (this->job) + if (this->heartbeat_active) { DBG1(DBG_CFG, "HA heartbeat active, dropping all segments"); deactivate(this, 0, TRUE); @@ -269,7 +269,7 @@ static job_requeue_t watchdog(private_ha_segments_t *this) DBG1(DBG_CFG, "no heartbeat received, taking all segments"); activate(this, 0, TRUE); /* disable heartbeat detection util we get one */ - this->job = NULL; + this->heartbeat_active = FALSE; return JOB_REQUEUE_NONE; } return JOB_REQUEUE_DIRECT; @@ -280,9 +280,10 @@ static job_requeue_t watchdog(private_ha_segments_t *this) */ static void start_watchdog(private_ha_segments_t *this) { - this->job = callback_job_create_with_prio((callback_job_cb_t)watchdog, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + this->heartbeat_active = TRUE; + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)watchdog, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); } METHOD(ha_segments_t, handle_status, void, @@ -312,10 +313,10 @@ METHOD(ha_segments_t, handle_status, void, } } - this->mutex->unlock(this->mutex); this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); - if (!this->job) + if (!this->heartbeat_active) { DBG1(DBG_CFG, "received heartbeat, reenabling watchdog"); start_watchdog(this); @@ -344,12 +345,7 @@ static job_requeue_t send_status(private_ha_segments_t *this) message->destroy(message); /* schedule next invocation */ - lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) - callback_job_create((callback_job_cb_t) - send_status, this, NULL, NULL), - this->heartbeat_delay); - - return JOB_REQUEUE_NONE; + return JOB_RESCHEDULE_MS(this->heartbeat_delay); } METHOD(ha_segments_t, is_active, bool, @@ -361,10 +357,6 @@ METHOD(ha_segments_t, is_active, bool, METHOD(ha_segments_t, destroy, void, private_ha_segments_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } this->mutex->destroy(this->mutex); this->condvar->destroy(this->condvar); free(this); @@ -398,9 +390,11 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), .heartbeat_delay = lib->settings->get_int(lib->settings, - "charon.plugins.ha.heartbeat_delay", DEFAULT_HEARTBEAT_DELAY), + "%s.plugins.ha.heartbeat_delay", DEFAULT_HEARTBEAT_DELAY, + charon->name), .heartbeat_timeout = lib->settings->get_int(lib->settings, - "charon.plugins.ha.heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT), + "%s.plugins.ha.heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT, + charon->name), ); if (monitor) diff --git a/src/libcharon/plugins/ha/ha_socket.c b/src/libcharon/plugins/ha/ha_socket.c index c02cf1021..5196a5dc7 100644 --- a/src/libcharon/plugins/ha/ha_socket.c +++ b/src/libcharon/plugins/ha/ha_socket.c @@ -138,6 +138,7 @@ METHOD(ha_socket_t, pull, ha_message_t*, DBG1(DBG_CFG, "pulling HA message failed: %s", strerror(errno)); sleep(1); + continue; } } message = ha_message_parse(chunk_create(buf, len)); diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 299053ec1..541dd9313 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -203,12 +203,13 @@ static void setup_tunnel(private_ha_tunnel_t *this, lib->credmgr->add_set(lib->credmgr, &this->creds.public); /* create config and backend */ - ike_cfg = ike_cfg_create(FALSE, FALSE, local, IKEV2_UDP_PORT, - remote, IKEV2_UDP_PORT); + ike_cfg = ike_cfg_create(FALSE, FALSE, local, FALSE, + charon->socket->get_port(charon->socket, FALSE), + remote, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create("ha", 2, ike_cfg, CERT_NEVER_SEND, - UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, 30, - NULL, NULL, FALSE, NULL, NULL); + peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND, + UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30, + 0, FALSE, NULL, NULL); auth_cfg = auth_cfg_create(); auth_cfg->add(auth_cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); diff --git a/src/libcharon/plugins/led/Makefile.in b/src/libcharon/plugins/led/Makefile.in index 56684ee11..a78ca9701 100644 --- a/src/libcharon/plugins/led/Makefile.in +++ b/src/libcharon/plugins/led/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_led_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_led_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_led_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_led_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/led/led_listener.c b/src/libcharon/plugins/led/led_listener.c index 4aae2abe5..be80bcde2 100644 --- a/src/libcharon/plugins/led/led_listener.c +++ b/src/libcharon/plugins/led/led_listener.c @@ -189,9 +189,9 @@ METHOD(listener_t, ike_state_change, bool, METHOD(listener_t, message_hook, bool, private_led_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { - if (incoming || message->get_request(message)) + if (plain && (incoming || message->get_request(message))) { blink_activity(this); } @@ -230,11 +230,12 @@ led_listener_t *led_listener_create() }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .blink_time = lib->settings->get_int(lib->settings, - "charon.plugins.led.blink_time", 50), + "%s.plugins.led.blink_time", 50, charon->name), ); this->activity = open_led(lib->settings->get_str(lib->settings, - "charon.plugins.led.activity_led", NULL), &this->activity_max); + "%s.plugins.led.activity_led", NULL, charon->name), + &this->activity_max); set_led(this->activity, 0); return &this->public; diff --git a/src/libcharon/plugins/load_tester/Makefile.in b/src/libcharon/plugins/load_tester/Makefile.in index bbd20d4b9..cb11cff28 100644 --- a/src/libcharon/plugins/load_tester/Makefile.in +++ b/src/libcharon/plugins/load_tester/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_load_tester_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_load_tester_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_load_tester_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index 6bc6f91e4..735f17985 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -44,6 +44,11 @@ struct private_load_tester_config_t { */ char *remote; + /** + * Local address + */ + char *local; + /** * IP address pool */ @@ -89,6 +94,11 @@ struct private_load_tester_config_t { */ u_int dpd_delay; + /** + * DPD timeout (IKEv1 only) + */ + u_int dpd_timeout; + /** * incremental numbering of generated configs */ @@ -241,21 +251,32 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) if (this->port && num) { ike_cfg = ike_cfg_create(FALSE, FALSE, - "0.0.0.0", this->port + num - 1, this->remote, IKEV2_NATT_PORT); + this->local, FALSE, this->port + num - 1, + this->remote, FALSE, IKEV2_NATT_PORT); } else { ike_cfg = ike_cfg_create(FALSE, FALSE, - "0.0.0.0", IKEV2_UDP_PORT, this->remote, IKEV2_UDP_PORT); + this->local, FALSE, charon->socket->get_port(charon->socket, FALSE), + this->remote, FALSE, IKEV2_UDP_PORT); } ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal)); - peer_cfg = peer_cfg_create("load-test", 2, ike_cfg, + peer_cfg = peer_cfg_create("load-test", IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, /* keytries */ this->ike_rekey, 0, /* rekey, reauth */ 0, this->ike_rekey, /* jitter, overtime */ - FALSE, this->dpd_delay, /* mobike, dpddelay */ - this->vip ? this->vip->clone(this->vip) : NULL, - this->pool, FALSE, NULL, NULL); + FALSE, FALSE, /* mobike, aggressive mode */ + this->dpd_delay, /* dpd_delay */ + this->dpd_timeout, /* dpd_timeout */ + FALSE, NULL, NULL); + if (this->vip) + { + peer_cfg->add_virtual_ip(peer_cfg, this->vip->clone(this->vip)); + } + if (this->pool) + { + peer_cfg->add_pool(peer_cfg, this->pool); + } if (num) { /* initiator */ generate_auth_cfg(this, this->initiator_auth, peer_cfg, TRUE, num); @@ -335,41 +356,46 @@ load_tester_config_t *load_tester_config_create() ); if (lib->settings->get_bool(lib->settings, - "charon.plugins.load-tester.request_virtual_ip", FALSE)) + "%s.plugins.load-tester.request_virtual_ip", FALSE, charon->name)) { this->vip = host_create_from_string("0.0.0.0", 0); } this->pool = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.pool", NULL); + "%s.plugins.load-tester.pool", NULL, charon->name); this->remote = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.remote", "127.0.0.1"); + "%s.plugins.load-tester.remote", "127.0.0.1", charon->name); + this->local = lib->settings->get_str(lib->settings, + "%s.plugins.load-tester.local", "0.0.0.0", charon->name); this->proposal = proposal_create_from_string(PROTO_IKE, - lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.proposal", "aes128-sha1-modp768")); + lib->settings->get_str(lib->settings, + "%s.plugins.load-tester.proposal", "aes128-sha1-modp768", + charon->name)); if (!this->proposal) { /* fallback */ this->proposal = proposal_create_from_string(PROTO_IKE, "aes128-sha1-modp768"); } this->ike_rekey = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.ike_rekey", 0); + "%s.plugins.load-tester.ike_rekey", 0, charon->name); this->child_rekey = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.child_rekey", 600); + "%s.plugins.load-tester.child_rekey", 600, charon->name); this->dpd_delay = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.dpd_delay", 0); + "%s.plugins.load-tester.dpd_delay", 0, charon->name); + this->dpd_timeout = lib->settings->get_int(lib->settings, + "%s.plugins.load-tester.dpd_timeout", 0, charon->name); this->initiator_auth = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.initiator_auth", "pubkey"); + "%s.plugins.load-tester.initiator_auth", "pubkey", charon->name); this->responder_auth = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.responder_auth", "pubkey"); + "%s.plugins.load-tester.responder_auth", "pubkey", charon->name); this->initiator_id = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.initiator_id", NULL); + "%s.plugins.load-tester.initiator_id", NULL, charon->name); this->responder_id = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.responder_id", NULL); + "%s.plugins.load-tester.responder_id", NULL, charon->name); this->port = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.dynamic_port", 0); + "%s.plugins.load-tester.dynamic_port", 0, charon->name); this->peer_cfg = generate_config(this, 0); diff --git a/src/libcharon/plugins/load_tester/load_tester_creds.c b/src/libcharon/plugins/load_tester/load_tester_creds.c index c34ea73c5..6d3b6933d 100644 --- a/src/libcharon/plugins/load_tester/load_tester_creds.c +++ b/src/libcharon/plugins/load_tester/load_tester_creds.c @@ -321,9 +321,9 @@ load_tester_creds_t *load_tester_creds_create() char *pwd, *psk; psk = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.preshared_key", default_psk); + "%s.plugins.load-tester.preshared_key", default_psk, charon->name); pwd = lib->settings->get_str(lib->settings, - "charon.plugins.load-tester.eap_password", default_pwd); + "%s.plugins.load-tester.eap_password", default_pwd, charon->name); INIT(this, .public = { diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c index 440197260..ded6b2d20 100644 --- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c +++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c @@ -108,12 +108,6 @@ METHOD(kernel_ipsec_t, del_policy, status_t, return SUCCESS; } -METHOD(kernel_ipsec_t, bypass_socket, bool, - private_load_tester_ipsec_t *this, int fd, int family) -{ - return TRUE; -} - METHOD(kernel_ipsec_t, destroy, void, private_load_tester_ipsec_t *this) { @@ -141,7 +135,8 @@ load_tester_ipsec_t *load_tester_ipsec_create() .query_policy = _query_policy, .del_policy = _del_policy, .flush_policies = (void*)return_failed, - .bypass_socket = _bypass_socket, + .bypass_socket = (void*)return_true, + .enable_udp_decap = (void*)return_true, .destroy = _destroy, }, }, diff --git a/src/libcharon/plugins/load_tester/load_tester_listener.c b/src/libcharon/plugins/load_tester/load_tester_listener.c index 7c96f7d97..92073e62c 100644 --- a/src/libcharon/plugins/load_tester/load_tester_listener.c +++ b/src/libcharon/plugins/load_tester/load_tester_listener.c @@ -108,7 +108,8 @@ load_tester_listener_t *load_tester_listener_create(u_int shutdown_on) .destroy = _destroy, }, .delete_after_established = lib->settings->get_bool(lib->settings, - "charon.plugins.load-tester.delete_after_established", FALSE), + "%s.plugins.load-tester.delete_after_established", FALSE, + charon->name), .shutdown_on = shutdown_on, ); diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c index b260a9741..4a982d4b7 100644 --- a/src/libcharon/plugins/load_tester/load_tester_plugin.c +++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c @@ -28,8 +28,6 @@ #include #include -static const char *plugin_name = "load_tester"; - typedef struct private_load_tester_plugin_t private_load_tester_plugin_t; /** @@ -171,26 +169,78 @@ METHOD(plugin_t, get_name, char*, return "load-tester"; } -METHOD(plugin_t, destroy, void, - private_load_tester_plugin_t *this) +/** + * Register load_tester plugin features + */ +static bool register_load_tester(private_load_tester_plugin_t *this, + plugin_feature_t *feature, bool reg, void *data) { - this->iterations = -1; - this->mutex->lock(this->mutex); - while (this->running) + if (reg) { - this->condvar->wait(this->condvar, this->mutex); + u_int i, shutdown_on = 0; + + this->config = load_tester_config_create(); + this->creds = load_tester_creds_create(); + + charon->backends->add_backend(charon->backends, &this->config->backend); + lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set); + + if (lib->settings->get_bool(lib->settings, + "%s.plugins.load-tester.shutdown_when_complete", 0, charon->name)) + { + shutdown_on = this->iterations * this->initiators; + } + this->listener = load_tester_listener_create(shutdown_on); + charon->bus->add_listener(charon->bus, &this->listener->listener); + + for (i = 0; i < this->initiators; i++) + { + lib->processor->queue_job(lib->processor, (job_t*) + callback_job_create_with_prio((callback_job_cb_t)do_load_test, + this, NULL, NULL, JOB_PRIO_CRITICAL)); + } } - this->mutex->unlock(this->mutex); + else + { + this->iterations = -1; + this->mutex->lock(this->mutex); + while (this->running) + { + this->condvar->wait(this->condvar, this->mutex); + } + this->mutex->unlock(this->mutex); + charon->backends->remove_backend(charon->backends, &this->config->backend); + lib->credmgr->remove_set(lib->credmgr, &this->creds->credential_set); + charon->bus->remove_listener(charon->bus, &this->listener->listener); + this->config->destroy(this->config); + this->creds->destroy(this->creds); + this->listener->destroy(this->listener); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_load_tester_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_REGISTER(DH, load_tester_diffie_hellman_create), + PLUGIN_PROVIDE(DH, MODP_NULL), + PLUGIN_DEPENDS(CUSTOM, "load-tester"), + PLUGIN_CALLBACK((plugin_feature_callback_t)register_load_tester, NULL), + PLUGIN_PROVIDE(CUSTOM, "load-tester"), + PLUGIN_SDEPEND(PRIVKEY, KEY_RSA), + PLUGIN_SDEPEND(CERT_DECODE, CERT_ANY), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_load_tester_plugin_t *this) +{ hydra->kernel_interface->remove_ipsec_interface(hydra->kernel_interface, (kernel_ipsec_constructor_t)load_tester_ipsec_create); - charon->backends->remove_backend(charon->backends, &this->config->backend); - lib->credmgr->remove_set(lib->credmgr, &this->creds->credential_set); - charon->bus->remove_listener(charon->bus, &this->listener->listener); - this->config->destroy(this->config); - this->creds->destroy(this->creds); - this->listener->destroy(this->listener); - lib->crypto->remove_dh(lib->crypto, - (dh_constructor_t)load_tester_diffie_hellman_create); this->mutex->destroy(this->mutex); this->condvar->destroy(this->condvar); free(this); @@ -202,10 +252,9 @@ METHOD(plugin_t, destroy, void, plugin_t *load_tester_plugin_create() { private_load_tester_plugin_t *this; - u_int i, shutdown_on = 0; if (!lib->settings->get_bool(lib->settings, - "charon.plugins.load-tester.enable", FALSE)) + "%s.plugins.load-tester.enable", FALSE, charon->name)) { DBG1(DBG_CFG, "disabling load-tester plugin, not configured"); return NULL; @@ -215,49 +264,29 @@ plugin_t *load_tester_plugin_create() .public = { .plugin = { .get_name = _get_name, + .get_features = _get_features, .reload = (void*)return_false, .destroy = _destroy, }, }, .delay = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.delay", 0), + "%s.plugins.load-tester.delay", 0, charon->name), .iterations = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.iterations", 1), + "%s.plugins.load-tester.iterations", 1, charon->name), .initiators = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.initiators", 0), + "%s.plugins.load-tester.initiators", 0, charon->name), .init_limit = lib->settings->get_int(lib->settings, - "charon.plugins.load-tester.init_limit", 0), + "%s.plugins.load-tester.init_limit", 0, charon->name), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), - .config = load_tester_config_create(), - .creds = load_tester_creds_create(), ); - lib->crypto->add_dh(lib->crypto, MODP_NULL, plugin_name, - (dh_constructor_t)load_tester_diffie_hellman_create); - charon->backends->add_backend(charon->backends, &this->config->backend); - lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set); - - if (lib->settings->get_bool(lib->settings, - "charon.plugins.load-tester.shutdown_when_complete", 0)) - { - shutdown_on = this->iterations * this->initiators; - } - this->listener = load_tester_listener_create(shutdown_on); - charon->bus->add_listener(charon->bus, &this->listener->listener); - if (lib->settings->get_bool(lib->settings, - "charon.plugins.load-tester.fake_kernel", FALSE)) + "%s.plugins.load-tester.fake_kernel", FALSE, charon->name)) { hydra->kernel_interface->add_ipsec_interface(hydra->kernel_interface, (kernel_ipsec_constructor_t)load_tester_ipsec_create); } - for (i = 0; i < this->initiators; i++) - { - lib->processor->queue_job(lib->processor, (job_t*) - callback_job_create_with_prio((callback_job_cb_t)do_load_test, - this, NULL, NULL, JOB_PRIO_CRITICAL)); - } return &this->public.plugin; } diff --git a/src/libcharon/plugins/maemo/Makefile.in b/src/libcharon/plugins/maemo/Makefile.in index d2b9d9a34..dfcd1f6ef 100644 --- a/src/libcharon/plugins/maemo/Makefile.in +++ b/src/libcharon/plugins/maemo/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_maemo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_maemo_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_maemo_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 6675e1d21..cb2fc9ebb 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -323,17 +323,20 @@ static gboolean initiate_connection(private_maemo_service_t *this, NULL); } - ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", IKEV2_UDP_PORT, - hostname, IKEV2_UDP_PORT); + ike_cfg = ike_cfg_create(TRUE, FALSE, "0.0.0.0", FALSE, + charon->socket->get_port(charon->socket, FALSE), + hostname, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create(this->current, 2, ike_cfg, CERT_SEND_IF_ASKED, + peer_cfg = peer_cfg_create(this->current, IKEV2, ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ - host_create_from_string("0.0.0.0", 0) /* virt */, - NULL, FALSE, NULL, NULL); /* pool, mediation */ + TRUE, FALSE, /* mobike, aggressive */ + 0, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); @@ -354,12 +357,16 @@ static gboolean initiate_connection(private_maemo_service_t *this, 0, "255.255.255.255", 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); peer_cfg->add_child_cfg(peer_cfg, child_cfg); - /* get an additional reference because initiate consumes one */ - child_cfg->get_ref(child_cfg); /* get us an IKE_SA */ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + this->status = VPN_STATUS_CONNECTION_FAILED; + return FALSE; + } if (!ike_sa->get_peer_cfg(ike_sa)) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); @@ -373,6 +380,8 @@ static gboolean initiate_connection(private_maemo_service_t *this, this->public.listener.ike_state_change = _ike_state_change; charon->bus->add_listener(charon->bus, &this->public.listener); + /* get an additional reference because initiate consumes one */ + child_cfg->get_ref(child_cfg); if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { DBG1(DBG_CFG, "failed to initiate tunnel"); @@ -423,8 +432,10 @@ static job_requeue_t run(private_maemo_service_t *this) return JOB_REQUEUE_NONE; } -METHOD(maemo_service_t, destroy, void, - private_maemo_service_t *this) +/** + * Cancel the GLib Main Event Loop + */ +static bool cancel(private_maemo_service_t *this) { if (this->loop) { @@ -434,6 +445,12 @@ METHOD(maemo_service_t, destroy, void, } g_main_loop_unref(this->loop); } + return TRUE; +} + +METHOD(maemo_service_t, destroy, void, + private_maemo_service_t *this) +{ if (this->context) { osso_rpc_unset_cb_f(this->context, @@ -502,8 +519,8 @@ maemo_service_t *maemo_service_create() } lib->processor->queue_job(lib->processor, - (job_t*)callback_job_create_with_prio((callback_job_cb_t)run, - this, NULL, NULL, JOB_PRIO_CRITICAL)); + (job_t*)callback_job_create_with_prio((callback_job_cb_t)run, this, + NULL, (callback_job_cancel_t)cancel, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/medcli/Makefile.in b/src/libcharon/plugins/medcli/Makefile.in index b8983ad21..359533a60 100644 --- a/src/libcharon/plugins/medcli/Makefile.in +++ b/src/libcharon/plugins/medcli/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_medcli_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_medcli_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_medcli_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index ee3e95422..a1825effc 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -119,15 +119,16 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, return NULL; } ike_cfg = ike_cfg_create(FALSE, FALSE, - "0.0.0.0", IKEV2_UDP_PORT, address, IKEV2_UDP_PORT); + "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), + address, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); med_cfg = peer_cfg_create( - "mediation", 2, ike_cfg, + "mediation", IKEV2, ike_cfg, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ - NULL, NULL, /* vip, pool */ + TRUE, FALSE, /* mobike, aggressive */ + this->dpd, 0, /* DPD delay, timeout */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); @@ -159,12 +160,12 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, return NULL; } peer_cfg = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ - NULL, NULL, /* vip, pool */ + TRUE, FALSE, /* mobike, aggressive */ + this->dpd, 0, /* DPD delay, timeout */ FALSE, med_cfg, /* mediation, med by */ identification_create_from_encoding(ID_KEY_ID, other)); @@ -234,12 +235,12 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, return FALSE; } this->current = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ - NULL, NULL, /* vip, pool */ + TRUE, FALSE, /* mobike, aggressive */ + this->dpd, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); @@ -391,8 +392,9 @@ medcli_config_t *medcli_config_create(database_t *db) .db = db, .rekey = lib->settings->get_time(lib->settings, "medcli.rekey", 1200), .dpd = lib->settings->get_time(lib->settings, "medcli.dpd", 300), - .ike = ike_cfg_create(FALSE, FALSE, "0.0.0.0", IKEV2_UDP_PORT, - "0.0.0.0", IKEV2_UDP_PORT), + .ike = ike_cfg_create(FALSE, FALSE, + "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), + "0.0.0.0", FALSE, IKEV2_UDP_PORT), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); diff --git a/src/libcharon/plugins/medsrv/Makefile.in b/src/libcharon/plugins/medsrv/Makefile.in index 91df95cf0..ba27b8570 100644 --- a/src/libcharon/plugins/medsrv/Makefile.in +++ b/src/libcharon/plugins/medsrv/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_medsrv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_medsrv_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_medsrv_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index 6cacb34f6..ff33c53e1 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -88,12 +88,12 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, if (e->enumerate(e, &name)) { peer_cfg = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ - NULL, NULL, /* vip, pool */ + TRUE, FALSE, /* mobike, aggressiv */ + this->dpd, 0, /* DPD delay, timeout */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); @@ -140,7 +140,8 @@ medsrv_config_t *medsrv_config_create(database_t *db) .rekey = lib->settings->get_time(lib->settings, "medsrv.rekey", 1200), .dpd = lib->settings->get_time(lib->settings, "medsrv.dpd", 300), .ike = ike_cfg_create(FALSE, FALSE, - "0.0.0.0", IKEV2_UDP_PORT, "0.0.0.0", IKEV2_UDP_PORT), + "0.0.0.0", FALSE, charon->socket->get_port(charon->socket, FALSE), + "0.0.0.0", FALSE, IKEV2_UDP_PORT), ); this->ike->add_proposal(this->ike, proposal_create_default(PROTO_IKE)); diff --git a/src/libcharon/plugins/nm/Makefile.am b/src/libcharon/plugins/nm/Makefile.am deleted file mode 100644 index 8e12a72be..000000000 --- a/src/libcharon/plugins/nm/Makefile.am +++ /dev/null @@ -1,21 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon ${nm_CFLAGS} - -AM_CFLAGS = -rdynamic \ - -DNM_CA_DIR=\"${nm_ca_dir}\" - -if MONOLITHIC -noinst_LTLIBRARIES = libstrongswan-nm.la -else -plugin_LTLIBRARIES = libstrongswan-nm.la -endif - -libstrongswan_nm_la_SOURCES = \ - nm_plugin.h nm_plugin.c \ - nm_service.h nm_service.c \ - nm_creds.h nm_creds.c \ - nm_handler.h nm_handler.c - -libstrongswan_nm_la_LDFLAGS = -module -avoid-version -libstrongswan_nm_la_LIBADD = ${nm_LIBS} diff --git a/src/libcharon/plugins/nm/Makefile.in b/src/libcharon/plugins/nm/Makefile.in deleted file mode 100644 index d9ad2388e..000000000 --- a/src/libcharon/plugins/nm/Makefile.in +++ /dev/null @@ -1,621 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/libcharon/plugins/nm -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(plugindir)" -LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) -am__DEPENDENCIES_1 = -libstrongswan_nm_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_libstrongswan_nm_la_OBJECTS = nm_plugin.lo nm_service.lo \ - nm_creds.lo nm_handler.lo -libstrongswan_nm_la_OBJECTS = $(am_libstrongswan_nm_la_OBJECTS) -libstrongswan_nm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libstrongswan_nm_la_LDFLAGS) $(LDFLAGS) -o $@ -@MONOLITHIC_FALSE@am_libstrongswan_nm_la_rpath = -rpath $(plugindir) -@MONOLITHIC_TRUE@am_libstrongswan_nm_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libstrongswan_nm_la_SOURCES) -DIST_SOURCES = $(libstrongswan_nm_la_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon ${nm_CFLAGS} - -AM_CFLAGS = -rdynamic \ - -DNM_CA_DIR=\"${nm_ca_dir}\" - -@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-nm.la -@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-nm.la -libstrongswan_nm_la_SOURCES = \ - nm_plugin.h nm_plugin.c \ - nm_service.h nm_service.c \ - nm_creds.h nm_creds.c \ - nm_handler.h nm_handler.c - -libstrongswan_nm_la_LDFLAGS = -module -avoid-version -libstrongswan_nm_la_LIBADD = ${nm_LIBS} -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/nm/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/libcharon/plugins/nm/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ - } - -uninstall-pluginLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ - done - -clean-pluginLTLIBRARIES: - -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libstrongswan-nm.la: $(libstrongswan_nm_la_OBJECTS) $(libstrongswan_nm_la_DEPENDENCIES) - $(libstrongswan_nm_la_LINK) $(am_libstrongswan_nm_la_rpath) $(libstrongswan_nm_la_OBJECTS) $(libstrongswan_nm_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_creds.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_handler.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm_service.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(plugindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ - clean-pluginLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pluginLTLIBRARIES - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pluginLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ - ctags distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-pluginLTLIBRARIES install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-pluginLTLIBRARIES - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/libcharon/plugins/nm/nm_creds.c b/src/libcharon/plugins/nm/nm_creds.c deleted file mode 100644 index f8fae9504..000000000 --- a/src/libcharon/plugins/nm/nm_creds.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "nm_creds.h" - -#include -#include -#include - -#include -#include -#include - -typedef struct private_nm_creds_t private_nm_creds_t; - -/** - * private data of nm_creds - */ -struct private_nm_creds_t { - - /** - * public functions - */ - nm_creds_t public; - - /** - * List of trusted certificates, certificate_t* - */ - linked_list_t *certs; - - /** - * User name - */ - identification_t *user; - - /** - * User password - */ - char *pass; - - /** - * Private key decryption password / smartcard pin - */ - char *keypass; - - /** - * private key ID of smartcard key - */ - chunk_t keyid; - - /** - * users certificate - */ - certificate_t *usercert; - - /** - * users private key - */ - private_key_t *key; - - /** - * read/write lock - */ - rwlock_t *lock; -}; - -/** - * Enumerator for user certificate - */ -static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this, - certificate_type_t cert, key_type_t key) -{ - public_key_t *public; - - if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert)) - { - return NULL; - } - if (key != KEY_ANY) - { - public = this->usercert->get_public_key(this->usercert); - if (!public) - { - return NULL; - } - if (public->get_type(public) != key) - { - public->destroy(public); - return NULL; - } - public->destroy(public); - } - this->lock->read_lock(this->lock); - return enumerator_create_cleaner( - enumerator_create_single(this->usercert, NULL), - (void*)this->lock->unlock, this->lock); -} - -/** - * CA certificate enumerator data - */ -typedef struct { - /** ref to credential credential store */ - private_nm_creds_t *this; - /** type of key we are looking for */ - key_type_t key; - /** CA certificate ID */ - identification_t *id; -} cert_data_t; - -/** - * Destroy CA certificate enumerator data - */ -static void cert_data_destroy(cert_data_t *data) -{ - data->this->lock->unlock(data->this->lock); - free(data); -} - -/** - * Filter function for certificates enumerator - */ -static bool cert_filter(cert_data_t *data, certificate_t **in, - certificate_t **out) -{ - certificate_t *cert = *in; - public_key_t *public; - - public = cert->get_public_key(cert); - if (!public) - { - return FALSE; - } - if (data->key != KEY_ANY && public->get_type(public) != data->key) - { - public->destroy(public); - return FALSE; - } - if (data->id && data->id->get_type(data->id) == ID_KEY_ID && - public->has_fingerprint(public, data->id->get_encoding(data->id))) - { - public->destroy(public); - *out = cert; - return TRUE; - } - public->destroy(public); - if (data->id && !cert->has_subject(cert, data->id)) - { - return FALSE; - } - *out = cert; - return TRUE; -} - -/** - * Create enumerator for trusted certificates - */ -static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this, - key_type_t key, identification_t *id) -{ - cert_data_t *data; - - INIT(data, - .this = this, - .id = id, - .key = key, - ); - - this->lock->read_lock(this->lock); - return enumerator_create_filter( - this->certs->create_enumerator(this->certs), - (void*)cert_filter, data, (void*)cert_data_destroy); -} - -METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, - private_nm_creds_t *this, certificate_type_t cert, key_type_t key, - identification_t *id, bool trusted) -{ - if (id && this->usercert && - id->equals(id, this->usercert->get_subject(this->usercert))) - { - return create_usercert_enumerator(this, cert, key); - } - if (cert == CERT_X509 || cert == CERT_ANY) - { - return create_trusted_cert_enumerator(this, key, id); - } - return NULL; -} - -METHOD(credential_set_t, create_private_enumerator, enumerator_t*, - private_nm_creds_t *this, key_type_t type, identification_t *id) -{ - if (this->key == NULL) - { - return NULL; - } - if (type != KEY_ANY && type != this->key->get_type(this->key)) - { - return NULL; - } - if (id && id->get_type(id) != ID_ANY) - { - if (id->get_type(id) != ID_KEY_ID || - !this->key->has_fingerprint(this->key, id->get_encoding(id))) - { - return NULL; - } - } - this->lock->read_lock(this->lock); - return enumerator_create_cleaner(enumerator_create_single(this->key, NULL), - (void*)this->lock->unlock, this->lock); -} - -/** - * shared key enumerator implementation - */ -typedef struct { - enumerator_t public; - private_nm_creds_t *this; - shared_key_t *key; - bool done; -} shared_enumerator_t; - -METHOD(enumerator_t, shared_enumerate, bool, - shared_enumerator_t *this, shared_key_t **key, id_match_t *me, - id_match_t *other) -{ - if (this->done) - { - return FALSE; - } - *key = this->key; - if (me) - { - *me = ID_MATCH_PERFECT; - } - if (other) - { - *other = ID_MATCH_ANY; - } - this->done = TRUE; - return TRUE; -} - -METHOD(enumerator_t, shared_destroy, void, - shared_enumerator_t *this) -{ - this->key->destroy(this->key); - this->this->lock->unlock(this->this->lock); - free(this); -} - -METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, - private_nm_creds_t *this, shared_key_type_t type, identification_t *me, - identification_t *other) -{ - shared_enumerator_t *enumerator; - chunk_t key; - - this->lock->read_lock(this->lock); - - switch (type) - { - case SHARED_EAP: - case SHARED_IKE: - if (!this->pass || !this->user) - { - goto no_secret; - } - if (me && !me->equals(me, this->user)) - { - goto no_secret; - } - key = chunk_create(this->pass, strlen(this->pass)); - break; - case SHARED_PRIVATE_KEY_PASS: - if (!this->keypass) - { - goto no_secret; - } - key = chunk_create(this->keypass, strlen(this->keypass)); - break; - case SHARED_PIN: - if (!this->keypass || !me || - !chunk_equals(me->get_encoding(me), this->keyid)) - { - goto no_secret; - } - key = chunk_create(this->keypass, strlen(this->keypass)); - break; - default: - goto no_secret; - } - - INIT(enumerator, - .public = { - .enumerate = (void*)_shared_enumerate, - .destroy = _shared_destroy, - }, - .this = this, - ); - enumerator->key = shared_key_create(type, chunk_clone(key)); - return &enumerator->public; - -no_secret: - this->lock->unlock(this->lock); - return NULL; -} - -METHOD(nm_creds_t, add_certificate, void, - private_nm_creds_t *this, certificate_t *cert) -{ - this->lock->write_lock(this->lock); - this->certs->insert_last(this->certs, cert); - this->lock->unlock(this->lock); -} - -/** - * Load a certificate file - */ -static void load_ca_file(private_nm_creds_t *this, char *file) -{ - certificate_t *cert; - - /* We add the CA constraint, as many CAs miss it */ - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_FROM_FILE, file, BUILD_END); - if (!cert) - { - DBG1(DBG_CFG, "loading CA certificate '%s' failed", file); - } - else - { - DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert)); - x509_t *x509 = (x509_t*)cert; - if (!(x509->get_flags(x509) & X509_SELF_SIGNED)) - { - DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert)); - } - this->certs->insert_last(this->certs, cert); - } -} - -METHOD(nm_creds_t, load_ca_dir, void, - private_nm_creds_t *this, char *dir) -{ - enumerator_t *enumerator; - char *rel, *abs; - struct stat st; - - enumerator = enumerator_create_directory(dir); - if (enumerator) - { - while (enumerator->enumerate(enumerator, &rel, &abs, &st)) - { - /* skip '.', '..' and hidden files */ - if (rel[0] != '.') - { - if (S_ISDIR(st.st_mode)) - { - load_ca_dir(this, abs); - } - else if (S_ISREG(st.st_mode)) - { - load_ca_file(this, abs); - } - } - } - enumerator->destroy(enumerator); - } -} - -METHOD(nm_creds_t, set_username_password, void, - private_nm_creds_t *this, identification_t *id, char *password) -{ - this->lock->write_lock(this->lock); - DESTROY_IF(this->user); - this->user = id->clone(id); - free(this->pass); - this->pass = strdupnull(password); - this->lock->unlock(this->lock); -} - -METHOD(nm_creds_t, set_key_password, void, - private_nm_creds_t *this, char *password) -{ - this->lock->write_lock(this->lock); - free(this->keypass); - this->keypass = strdupnull(password); - this->lock->unlock(this->lock); -} - -METHOD(nm_creds_t, set_pin, void, - private_nm_creds_t *this, chunk_t keyid, char *pin) -{ - this->lock->write_lock(this->lock); - free(this->keypass); - free(this->keyid.ptr); - this->keypass = strdupnull(pin); - this->keyid = chunk_clone(keyid); - this->lock->unlock(this->lock); -} - -METHOD(nm_creds_t, set_cert_and_key, void, - private_nm_creds_t *this, certificate_t *cert, private_key_t *key) -{ - this->lock->write_lock(this->lock); - DESTROY_IF(this->key); - DESTROY_IF(this->usercert); - this->key = key; - this->usercert = cert; - this->lock->unlock(this->lock); -} - -METHOD(nm_creds_t, clear, void, - private_nm_creds_t *this) -{ - certificate_t *cert; - - while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS) - { - cert->destroy(cert); - } - DESTROY_IF(this->user); - free(this->pass); - free(this->keypass); - free(this->keyid.ptr); - DESTROY_IF(this->usercert); - DESTROY_IF(this->key); - this->key = NULL; - this->usercert = NULL; - this->pass = NULL; - this->user = NULL; - this->keypass = NULL; - this->keyid = chunk_empty; -} - -METHOD(nm_creds_t, destroy, void, - private_nm_creds_t *this) -{ - clear(this); - this->certs->destroy(this->certs); - this->lock->destroy(this->lock); - free(this); -} - -/* - * see header file - */ -nm_creds_t *nm_creds_create() -{ - private_nm_creds_t *this; - - INIT(this, - .public = { - .set = { - .create_private_enumerator = _create_private_enumerator, - .create_cert_enumerator = _create_cert_enumerator, - .create_shared_enumerator = _create_shared_enumerator, - .create_cdp_enumerator = (void*)return_null, - .cache_cert = (void*)nop, - }, - .add_certificate = _add_certificate, - .load_ca_dir = _load_ca_dir, - .set_username_password = _set_username_password, - .set_key_password = _set_key_password, - .set_pin = _set_pin, - .set_cert_and_key = _set_cert_and_key, - .clear = _clear, - .destroy = _destroy, - }, - .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), - .certs = linked_list_create(), - ); - return &this->public; -} - diff --git a/src/libcharon/plugins/nm/nm_creds.h b/src/libcharon/plugins/nm/nm_creds.h deleted file mode 100644 index 91f645c7e..000000000 --- a/src/libcharon/plugins/nm/nm_creds.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup nm_creds nm_creds - * @{ @ingroup nm - */ - -#ifndef NM_CREDS_H_ -#define NM_CREDS_H_ - -#include -#include - -typedef struct nm_creds_t nm_creds_t; - -/** - * NetworkManager credentials helper. - */ -struct nm_creds_t { - - /** - * Implements credential_set_t - */ - credential_set_t set; - - /** - * Add a trusted gateway certificate to serve by this set. - * - * @param cert certificate to serve - */ - void (*add_certificate)(nm_creds_t *this, certificate_t *cert); - - /** - * Load CA certificates recursively from a directory. - * - * @param dir directory to PEM encoded CA certificates - */ - void (*load_ca_dir)(nm_creds_t *this, char *dir); - - /** - * Set the username/password for authentication. - * - * @param id ID of the user - * @param password password to use for authentication - */ - void (*set_username_password)(nm_creds_t *this, identification_t *id, - char *password); - - /** - * Set the passphrase to use for private key decryption. - * - * @param password password to use - */ - void (*set_key_password)(nm_creds_t *this, char *password); - - /** - * Set the PIN to unlock a smartcard. - * - * @param keyid keyid of the smartcard key - * @param pin PIN - */ - void (*set_pin)(nm_creds_t *this, chunk_t keyid, char *pin); - - /** - * Set the certificate and private key to use for client authentication. - * - * @param cert client certificate - * @param key associated private key - */ - void (*set_cert_and_key)(nm_creds_t *this, certificate_t *cert, - private_key_t *key); - - /** - * Clear the stored credentials. - */ - void (*clear)(nm_creds_t *this); - - /** - * Destroy a nm_creds instance. - */ - void (*destroy)(nm_creds_t *this); -}; - -/** - * Create a nm_creds instance. - */ -nm_creds_t *nm_creds_create(); - -#endif /** NM_CREDS_H_ @}*/ diff --git a/src/libcharon/plugins/nm/nm_handler.c b/src/libcharon/plugins/nm/nm_handler.c deleted file mode 100644 index 408129ebe..000000000 --- a/src/libcharon/plugins/nm/nm_handler.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "nm_handler.h" - -#include - -typedef struct private_nm_handler_t private_nm_handler_t; - -/** - * Private data of an nm_handler_t object. - */ -struct private_nm_handler_t { - - /** - * Public nm_handler_t interface. - */ - nm_handler_t public; - - /** - * list of received DNS server attributes, pointer to 4 byte data - */ - linked_list_t *dns; - - /** - * list of received NBNS server attributes, pointer to 4 byte data - */ - linked_list_t *nbns; -}; - -METHOD(attribute_handler_t, handle, bool, - private_nm_handler_t *this, identification_t *server, - configuration_attribute_type_t type, chunk_t data) -{ - linked_list_t *list; - - switch (type) - { - case INTERNAL_IP4_DNS: - list = this->dns; - break; - case INTERNAL_IP4_NBNS: - list = this->nbns; - break; - default: - return FALSE; - } - if (data.len != 4) - { - return FALSE; - } - list->insert_last(list, chunk_clone(data).ptr); - return TRUE; -} - -/** - * Implementation of create_attribute_enumerator().enumerate() for WINS - */ -static bool enumerate_nbns(enumerator_t *this, - configuration_attribute_type_t *type, chunk_t *data) -{ - *type = INTERNAL_IP4_NBNS; - *data = chunk_empty; - /* done */ - this->enumerate = (void*)return_false; - return TRUE; -} - -/** - * Implementation of create_attribute_enumerator().enumerate() for DNS - */ -static bool enumerate_dns(enumerator_t *this, - configuration_attribute_type_t *type, chunk_t *data) -{ - *type = INTERNAL_IP4_DNS; - *data = chunk_empty; - /* enumerate WINS server as next attribute ... */ - this->enumerate = (void*)enumerate_nbns; - return TRUE; -} - -METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, - private_nm_handler_t *this, identification_t *server, host_t *vip) -{ - if (vip && vip->get_family(vip) == AF_INET) - { /* no IPv6 attributes yet */ - enumerator_t *enumerator = malloc_thing(enumerator_t); - /* enumerate DNS attribute first ... */ - enumerator->enumerate = (void*)enumerate_dns; - enumerator->destroy = (void*)free; - - return enumerator; - } - return enumerator_create_empty(); -} - -/** - * convert plain byte ptrs to handy chunk during enumeration - */ -static bool filter_chunks(void* null, char **in, chunk_t *out) -{ - *out = chunk_create(*in, 4); - return TRUE; -} - -METHOD(nm_handler_t, create_enumerator, enumerator_t*, - private_nm_handler_t *this, configuration_attribute_type_t type) -{ - linked_list_t *list; - - switch (type) - { - case INTERNAL_IP4_DNS: - list = this->dns; - break; - case INTERNAL_IP4_NBNS: - list = this->nbns; - break; - default: - return enumerator_create_empty(); - } - return enumerator_create_filter(list->create_enumerator(list), - (void*)filter_chunks, NULL, NULL); -} - -METHOD(nm_handler_t, reset, void, - private_nm_handler_t *this) -{ - void *data; - - while (this->dns->remove_last(this->dns, (void**)&data) == SUCCESS) - { - free(data); - } - while (this->nbns->remove_last(this->nbns, (void**)&data) == SUCCESS) - { - free(data); - } -} - -METHOD(nm_handler_t, destroy, void, - private_nm_handler_t *this) -{ - reset(this); - this->dns->destroy(this->dns); - this->nbns->destroy(this->nbns); - free(this); -} - -/** - * See header - */ -nm_handler_t *nm_handler_create() -{ - private_nm_handler_t *this; - - INIT(this, - .public = { - .handler = { - .handle = _handle, - .release = nop, - .create_attribute_enumerator = _create_attribute_enumerator, - }, - .create_enumerator = _create_enumerator, - .reset = _reset, - .destroy = _destroy, - }, - .dns = linked_list_create(), - .nbns = linked_list_create(), - ); - - return &this->public; -} - diff --git a/src/libcharon/plugins/nm/nm_handler.h b/src/libcharon/plugins/nm/nm_handler.h deleted file mode 100644 index bb35ce767..000000000 --- a/src/libcharon/plugins/nm/nm_handler.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup nm_handler nm_handler - * @{ @ingroup nm - */ - -#ifndef NM_HANDLER_H_ -#define NM_HANDLER_H_ - -#include - -typedef struct nm_handler_t nm_handler_t; - -/** - * Handles DNS/NBNS attributes to pass to NM. - */ -struct nm_handler_t { - - /** - * Implements attribute handler interface - */ - attribute_handler_t handler; - - /** - * Create an enumerator over received attributes of a given kind. - * - * @param type type of attributes to enumerate - * @return enumerator over attribute data (chunk_t) - */ - enumerator_t* (*create_enumerator)(nm_handler_t *this, - configuration_attribute_type_t type); - /** - * Reset state, flush all received attributes. - */ - void (*reset)(nm_handler_t *this); - - /** - * Destroy a nm_handler_t. - */ - void (*destroy)(nm_handler_t *this); -}; - -/** - * Create a nm_handler instance. - */ -nm_handler_t *nm_handler_create(); - -#endif /** NM_HANDLER_H_ @}*/ diff --git a/src/libcharon/plugins/nm/nm_plugin.c b/src/libcharon/plugins/nm/nm_plugin.c deleted file mode 100644 index 84b7c810a..000000000 --- a/src/libcharon/plugins/nm/nm_plugin.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2008-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "nm_plugin.h" -#include "nm_service.h" -#include "nm_creds.h" -#include "nm_handler.h" - -#include -#include -#include - -#define CAP_DAC_OVERRIDE 1 - -typedef struct private_nm_plugin_t private_nm_plugin_t; - -/** - * private data of nm plugin - */ -struct private_nm_plugin_t { - - /** - * implements plugin interface - */ - nm_plugin_t public; - - /** - * NetworkManager service (VPNPlugin) - */ - NMStrongswanPlugin *plugin; - - /** - * Glib main loop for a thread, handles DBUS calls - */ - GMainLoop *loop; - - /** - * credential set registered at the daemon - */ - nm_creds_t *creds; - - /** - * attribute handler regeisterd at the daemon - */ - nm_handler_t *handler; -}; - -/** - * NM plugin processing routine, creates and handles NMVPNPlugin - */ -static job_requeue_t run(private_nm_plugin_t *this) -{ - this->loop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(this->loop); - return JOB_REQUEUE_NONE; -} - -METHOD(plugin_t, get_name, char*, - private_nm_plugin_t *this) -{ - return "nm"; -} - -METHOD(plugin_t, destroy, void, - private_nm_plugin_t *this) -{ - if (this->loop) - { - if (g_main_loop_is_running(this->loop)) - { - g_main_loop_quit(this->loop); - } - g_main_loop_unref(this->loop); - } - if (this->plugin) - { - g_object_unref(this->plugin); - } - lib->credmgr->remove_set(lib->credmgr, &this->creds->set); - hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler); - this->creds->destroy(this->creds); - this->handler->destroy(this->handler); - free(this); -} - -/* - * see header file - */ -plugin_t *nm_plugin_create() -{ - private_nm_plugin_t *this; - - g_type_init (); - if (!g_thread_supported()) - { - g_thread_init(NULL); - } - - INIT(this, - .public = { - .plugin = { - .get_name = _get_name, - .reload = (void*)return_false, - .destroy = _destroy, - }, - }, - .creds = nm_creds_create(), - .handler = nm_handler_create(), - ); - this->plugin = nm_strongswan_plugin_new(this->creds, this->handler); - - hydra->attributes->add_handler(hydra->attributes, &this->handler->handler); - lib->credmgr->add_set(lib->credmgr, &this->creds->set); - if (!this->plugin) - { - DBG1(DBG_CFG, "DBUS binding failed"); - destroy(this); - return NULL; - } - - /* bypass file permissions to read from users ssh-agent */ - charon->keep_cap(charon, CAP_DAC_OVERRIDE); - - lib->processor->queue_job(lib->processor, - (job_t*)callback_job_create_with_prio((callback_job_cb_t)run, - this, NULL, NULL, JOB_PRIO_CRITICAL)); - - return &this->public.plugin; -} - diff --git a/src/libcharon/plugins/nm/nm_plugin.h b/src/libcharon/plugins/nm/nm_plugin.h deleted file mode 100644 index b64b3edf6..000000000 --- a/src/libcharon/plugins/nm/nm_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup nm nm - * @ingroup cplugins - * - * @defgroup nm_plugin nm_plugin - * @{ @ingroup nm - */ - -#ifndef NM_PLUGIN_H_ -#define NM_PLUGIN_H_ - -#include - -typedef struct nm_plugin_t nm_plugin_t; - -/** - * NetworkManager integration plugin. - */ -struct nm_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** NM_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c deleted file mode 100644 index a6783fcc3..000000000 --- a/src/libcharon/plugins/nm/nm_service.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * Copyright (C) 2008-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include "nm_service.h" - -#include -#include -#include -#include -#include - -#include - -G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_PLUGIN) - -/** - * Private data of NMStrongswanPlugin - */ -typedef struct { - /* implements bus listener interface */ - listener_t listener; - /* IKE_SA we are listening on */ - ike_sa_t *ike_sa; - /* backref to public plugin */ - NMVPNPlugin *plugin; - /* credentials to use for authentication */ - nm_creds_t *creds; - /* attribute handler for DNS/NBNS server information */ - nm_handler_t *handler; - /* name of the connection */ - char *name; -} NMStrongswanPluginPrivate; - -#define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate)) - -/** - * convert enumerated handler chunks to a UINT_ARRAY GValue - */ -static GValue* handler_to_val(nm_handler_t *handler, - configuration_attribute_type_t type) -{ - GValue *val; - GArray *array; - enumerator_t *enumerator; - chunk_t chunk; - - enumerator = handler->create_enumerator(handler, type); - array = g_array_new (FALSE, TRUE, sizeof (guint32)); - while (enumerator->enumerate(enumerator, &chunk)) - { - g_array_append_val (array, *(u_int32_t*)chunk.ptr); - } - enumerator->destroy(enumerator); - val = g_slice_new0 (GValue); - g_value_init (val, DBUS_TYPE_G_UINT_ARRAY); - g_value_set_boxed (val, array); - - return val; -} - -/** - * signal IPv4 config to NM, set connection as established - */ -static void signal_ipv4_config(NMVPNPlugin *plugin, - ike_sa_t *ike_sa, child_sa_t *child_sa) -{ - GValue *val; - GHashTable *config; - host_t *me; - nm_handler_t *handler; - - config = g_hash_table_new(g_str_hash, g_str_equal); - me = ike_sa->get_my_host(ike_sa); - handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler; - - /* NM requires a tundev, but netkey does not use one. Passing an invalid - * iface makes NM complain, but it accepts it without fiddling on eth0. */ - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, "none"); - g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, val); - - val = g_slice_new0(GValue); - g_value_init(val, G_TYPE_UINT); - g_value_set_uint(val, *(u_int32_t*)me->get_address(me).ptr); - g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val); - - val = g_slice_new0(GValue); - g_value_init(val, G_TYPE_UINT); - g_value_set_uint(val, me->get_address(me).len * 8); - g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); - - val = handler_to_val(handler, INTERNAL_IP4_DNS); - g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val); - - val = handler_to_val(handler, INTERNAL_IP4_NBNS); - g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val); - - handler->reset(handler); - - nm_vpn_plugin_set_ip4_config(plugin, config); -} - -/** - * signal failure to NM, connecting failed - */ -static void signal_failure(NMVPNPlugin *plugin, NMVPNPluginFailure failure) -{ - nm_handler_t *handler = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->handler; - - handler->reset(handler); - - /* TODO: NM does not handle this failure!? */ - nm_vpn_plugin_failure(plugin, failure); - nm_vpn_plugin_set_state(plugin, NM_VPN_SERVICE_STATE_STOPPED); -} - -/** - * Implementation of listener_t.ike_state_change - */ -static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa, - ike_sa_state_t state) -{ - NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; - - if (private->ike_sa == ike_sa && state == IKE_DESTROYING) - { - signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED); - return FALSE; - } - return TRUE; -} - -/** - * Implementation of listener_t.child_state_change - */ -static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa, - child_sa_t *child_sa, child_sa_state_t state) -{ - NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; - - if (private->ike_sa == ike_sa && state == CHILD_DESTROYING) - { - signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); - return FALSE; - } - return TRUE; -} - -/** - * Implementation of listener_t.child_updown - */ -static bool child_updown(listener_t *listener, ike_sa_t *ike_sa, - child_sa_t *child_sa, bool up) -{ - NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; - - if (private->ike_sa == ike_sa) - { - if (up) - { /* disable initiate-failure-detection hooks */ - private->listener.ike_state_change = NULL; - private->listener.child_state_change = NULL; - signal_ipv4_config(private->plugin, ike_sa, child_sa); - } - else - { - signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); - return FALSE; - } - } - return TRUE; -} - -/** - * Implementation of listener_t.ike_rekey - */ -static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new) -{ - NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; - - if (private->ike_sa == old) - { /* follow a rekeyed IKE_SA */ - private->ike_sa = new; - } - return TRUE; -} - -/** - * Find a certificate for which we have a private key on a smartcard - */ -static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv, - char *pin) -{ - enumerator_t *enumerator, *sans; - identification_t *id = NULL; - certificate_t *cert; - x509_t *x509; - private_key_t *key; - chunk_t keyid; - - enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, - CERT_X509, KEY_ANY, NULL, FALSE); - while (enumerator->enumerate(enumerator, &cert)) - { - x509 = (x509_t*)cert; - - /* there might be a lot of certificates, filter them by usage */ - if ((x509->get_flags(x509) & X509_CLIENT_AUTH) && - !(x509->get_flags(x509) & X509_CA)) - { - keyid = x509->get_subjectKeyIdentifier(x509); - if (keyid.ptr) - { - /* try to find a private key by the certificate keyid */ - priv->creds->set_pin(priv->creds, keyid, pin); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END); - if (key) - { - /* prefer a more convenient subjectAltName */ - sans = x509->create_subjectAltName_enumerator(x509); - if (!sans->enumerate(sans, &id)) - { - id = cert->get_subject(cert); - } - id = id->clone(id); - sans->destroy(sans); - - DBG1(DBG_CFG, "using smartcard certificate '%Y'", id); - priv->creds->set_cert_and_key(priv->creds, - cert->get_ref(cert), key); - break; - } - } - } - } - enumerator->destroy(enumerator); - return id; -} - -/** - * Connect function called from NM via DBUS - */ -static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, - GError **err) -{ - NMStrongswanPluginPrivate *priv; - NMSettingConnection *conn; - NMSettingVPN *vpn; - identification_t *user = NULL, *gateway = NULL; - const char *address, *str; - bool virtual, encap, ipcomp; - ike_cfg_t *ike_cfg; - peer_cfg_t *peer_cfg; - child_cfg_t *child_cfg; - traffic_selector_t *ts; - ike_sa_t *ike_sa; - auth_cfg_t *auth; - auth_class_t auth_class = AUTH_CLASS_EAP; - certificate_t *cert = NULL; - x509_t *x509; - bool agent = FALSE, smartcard = FALSE; - lifetime_cfg_t lifetime = { - .time = { - .life = 10800 /* 3h */, - .rekey = 10200 /* 2h50min */, - .jitter = 300 /* 5min */ - } - }; - - /** - * Read parameters - */ - priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); - conn = NM_SETTING_CONNECTION(nm_connection_get_setting(connection, - NM_TYPE_SETTING_CONNECTION)); - vpn = NM_SETTING_VPN(nm_connection_get_setting(connection, - NM_TYPE_SETTING_VPN)); - if (priv->name) - { - free(priv->name); - } - priv->name = strdup(nm_setting_connection_get_id(conn)); - DBG1(DBG_CFG, "received initiate for NetworkManager connection %s", - priv->name); - DBG4(DBG_CFG, "%s", - nm_setting_to_string(NM_SETTING(vpn))); - address = nm_setting_vpn_get_data_item(vpn, "address"); - if (!address || !*address) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Gateway address missing."); - return FALSE; - } - str = nm_setting_vpn_get_data_item(vpn, "virtual"); - virtual = str && streq(str, "yes"); - str = nm_setting_vpn_get_data_item(vpn, "encap"); - encap = str && streq(str, "yes"); - str = nm_setting_vpn_get_data_item(vpn, "ipcomp"); - ipcomp = str && streq(str, "yes"); - str = nm_setting_vpn_get_data_item(vpn, "method"); - if (str) - { - if (streq(str, "psk")) - { - auth_class = AUTH_CLASS_PSK; - } - else if (streq(str, "agent")) - { - auth_class = AUTH_CLASS_PUBKEY; - agent = TRUE; - } - else if (streq(str, "key")) - { - auth_class = AUTH_CLASS_PUBKEY; - } - else if (streq(str, "smartcard")) - { - auth_class = AUTH_CLASS_PUBKEY; - smartcard = TRUE; - } - } - - /** - * Register credentials - */ - priv->creds->clear(priv->creds); - - /* gateway/CA cert */ - str = nm_setting_vpn_get_data_item(vpn, "certificate"); - if (str) - { - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_FROM_FILE, str, BUILD_END); - if (!cert) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Loading gateway certificate failed."); - return FALSE; - } - priv->creds->add_certificate(priv->creds, cert); - - x509 = (x509_t*)cert; - if (!(x509->get_flags(x509) & X509_CA)) - { /* For a gateway certificate, we use the cert subject as identity. */ - gateway = cert->get_subject(cert); - gateway = gateway->clone(gateway); - DBG1(DBG_CFG, "using gateway certificate, identity '%Y'", gateway); - } - } - else - { - /* no certificate defined, fall back to system-wide CA certificates */ - priv->creds->load_ca_dir(priv->creds, NM_CA_DIR); - } - if (!gateway) - { - /* If the user configured a CA certificate, we use the IP/DNS - * of the gateway as its identity. This identity will be used for - * certificate lookup and requires the configured IP/DNS to be - * included in the gateway certificate. */ - gateway = identification_create_from_string((char*)address); - DBG1(DBG_CFG, "using CA certificate, gateway identity '%Y'", gateway); - } - - if (auth_class == AUTH_CLASS_EAP) - { - /* username/password authentication ... */ - str = nm_setting_vpn_get_data_item(vpn, "user"); - if (str) - { - user = identification_create_from_string((char*)str); - str = nm_setting_vpn_get_secret(vpn, "password"); - priv->creds->set_username_password(priv->creds, user, (char*)str); - } - } - - if (auth_class == AUTH_CLASS_PUBKEY) - { - if (smartcard) - { - char *pin; - - pin = (char*)nm_setting_vpn_get_secret(vpn, "password"); - if (pin) - { - user = find_smartcard_key(priv, pin); - } - if (!user) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "no usable smartcard certificate found."); - gateway->destroy(gateway); - return FALSE; - } - } - /* ... or certificate/private key authenitcation */ - else if ((str = nm_setting_vpn_get_data_item(vpn, "usercert"))) - { - public_key_t *public; - private_key_t *private = NULL; - - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, - BUILD_FROM_FILE, str, BUILD_END); - if (!cert) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Loading peer certificate failed."); - gateway->destroy(gateway); - return FALSE; - } - /* try agent */ - str = nm_setting_vpn_get_secret(vpn, "agent"); - if (agent && str) - { - public = cert->get_public_key(cert); - if (public) - { - private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - public->get_type(public), - BUILD_AGENT_SOCKET, str, - BUILD_PUBLIC_KEY, public, - BUILD_END); - public->destroy(public); - } - if (!private) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Connecting to SSH agent failed."); - } - } - /* ... or key file */ - str = nm_setting_vpn_get_data_item(vpn, "userkey"); - if (!agent && str) - { - char *secret; - - secret = (char*)nm_setting_vpn_get_secret(vpn, "password"); - if (secret) - { - priv->creds->set_key_password(priv->creds, secret); - } - private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - KEY_RSA, BUILD_FROM_FILE, str, BUILD_END); - if (!private) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, - NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Loading private key failed."); - } - } - if (private) - { - user = cert->get_subject(cert); - user = user->clone(user); - priv->creds->set_cert_and_key(priv->creds, cert, private); - } - else - { - DESTROY_IF(cert); - gateway->destroy(gateway); - return FALSE; - } - } - } - - if (!user) - { - g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, - "Configuration parameters missing."); - gateway->destroy(gateway); - return FALSE; - } - - /** - * Set up configurations - */ - ike_cfg = ike_cfg_create(TRUE, encap, - "0.0.0.0", IKEV2_UDP_PORT, (char*)address, IKEV2_UDP_PORT); - ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create(priv->name, 2, ike_cfg, - CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ - 36000, 0, /* rekey 10h, reauth none */ - 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ - virtual ? host_create_from_string("0.0.0.0", 0) : NULL, - NULL, FALSE, NULL, NULL); /* pool, mediation */ - auth = auth_cfg_create(); - auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class); - auth->add(auth, AUTH_RULE_IDENTITY, user); - peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); - auth = auth_cfg_create(); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - auth->add(auth, AUTH_RULE_IDENTITY, gateway); - peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); - - child_cfg = child_cfg_create(priv->name, &lifetime, - NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */ - ACTION_NONE, ACTION_NONE, ACTION_NONE, ipcomp, - 0, 0, NULL, NULL, 0); - child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); - ts = traffic_selector_create_dynamic(0, 0, 65535); - child_cfg->add_traffic_selector(child_cfg, TRUE, ts); - ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, - "0.0.0.0", 0, - "255.255.255.255", 65535); - child_cfg->add_traffic_selector(child_cfg, FALSE, ts); - peer_cfg->add_child_cfg(peer_cfg, child_cfg); - - /** - * Prepare IKE_SA - */ - ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, - peer_cfg); - if (!ike_sa->get_peer_cfg(ike_sa)) - { - ike_sa->set_peer_cfg(ike_sa, peer_cfg); - } - peer_cfg->destroy(peer_cfg); - - /** - * Register listener, enable initiate-failure-detection hooks - */ - priv->ike_sa = ike_sa; - priv->listener.ike_state_change = ike_state_change; - priv->listener.child_state_change = child_state_change; - charon->bus->add_listener(charon->bus, &priv->listener); - - /** - * Initiate - */ - if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) - { - charon->bus->remove_listener(charon->bus, &priv->listener); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); - - g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, - "Initiating failed."); - return FALSE; - } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return TRUE; -} - -/** - * NeedSecrets called from NM via DBUS - */ -static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, - char **setting_name, GError **error) -{ - NMSettingVPN *settings; - const char *method, *path; - - settings = NM_SETTING_VPN(nm_connection_get_setting(connection, - NM_TYPE_SETTING_VPN)); - method = nm_setting_vpn_get_data_item(settings, "method"); - if (method) - { - if (streq(method, "eap")) - { - if (nm_setting_vpn_get_secret(settings, "password")) - { - return FALSE; - } - } - else if (streq(method, "agent")) - { - if (nm_setting_vpn_get_secret(settings, "agent")) - { - return FALSE; - } - } - else if (streq(method, "key")) - { - path = nm_setting_vpn_get_data_item(settings, "userkey"); - if (path) - { - private_key_t *key; - - /* try to load/decrypt the private key */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, - KEY_RSA, BUILD_FROM_FILE, path, BUILD_END); - if (key) - { - key->destroy(key); - return FALSE; - } - } - } - else if streq(method, "smartcard") - { - if (nm_setting_vpn_get_secret(settings, "password")) - { - return FALSE; - } - } - } - *setting_name = NM_SETTING_VPN_SETTING_NAME; - return TRUE; -} - -/** - * Disconnect called from NM via DBUS - */ -static gboolean disconnect(NMVPNPlugin *plugin, GError **err) -{ - NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); - enumerator_t *enumerator; - ike_sa_t *ike_sa; - u_int id; - - /* our ike_sa pointer might be invalid, lookup sa */ - enumerator = charon->controller->create_ike_sa_enumerator( - charon->controller, TRUE); - while (enumerator->enumerate(enumerator, &ike_sa)) - { - if (priv->ike_sa == ike_sa) - { - id = ike_sa->get_unique_id(ike_sa); - enumerator->destroy(enumerator); - charon->controller->terminate_ike(charon->controller, id, - controller_cb_empty, NULL, 0); - return TRUE; - } - } - enumerator->destroy(enumerator); - - g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_GENERAL, - "Connection not found."); - return FALSE; -} - -/** - * Initializer - */ -static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin) -{ - NMStrongswanPluginPrivate *priv; - - priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); - priv->plugin = NM_VPN_PLUGIN(plugin); - memset(&priv->listener.log, 0, sizeof(listener_t)); - priv->listener.child_updown = child_updown; - priv->listener.ike_rekey = ike_rekey; -} - -/** - * Class constructor - */ -static void nm_strongswan_plugin_class_init( - NMStrongswanPluginClass *strongswan_class) -{ - NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS(strongswan_class); - - g_type_class_add_private(G_OBJECT_CLASS(strongswan_class), - sizeof(NMStrongswanPluginPrivate)); - parent_class->connect = connect_; - parent_class->need_secrets = need_secrets; - parent_class->disconnect = disconnect; -} - -/** - * Object constructor - */ -NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds, - nm_handler_t *handler) -{ - NMStrongswanPlugin *plugin = (NMStrongswanPlugin *)g_object_new ( - NM_TYPE_STRONGSWAN_PLUGIN, - NM_VPN_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_STRONGSWAN, - NULL); - if (plugin) - { - NMStrongswanPluginPrivate *priv; - - priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin); - priv->creds = creds; - priv->handler = handler; - priv->name = NULL; - } - return plugin; -} - diff --git a/src/libcharon/plugins/nm/nm_service.h b/src/libcharon/plugins/nm/nm_service.h deleted file mode 100644 index 828d1a452..000000000 --- a/src/libcharon/plugins/nm/nm_service.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2008-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup nm_service nm_service - * @{ @ingroup nm - */ - -#ifndef NM_SERVICE_H_ -#define NM_SERVICE_H_ - -#include -#include -#include - -#include "nm_creds.h" -#include "nm_handler.h" - -#define NM_TYPE_STRONGSWAN_PLUGIN (nm_strongswan_plugin_get_type ()) -#define NM_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPlugin)) -#define NM_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) -#define NM_IS_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) -#define NM_IS_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) -#define NM_STRONGSWAN_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) - -#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" -#define NM_DBUS_INTERFACE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" -#define NM_DBUS_PATH_STRONGSWAN "/org/freedesktop/NetworkManager/strongswan" - -typedef struct { - NMVPNPlugin parent; -} NMStrongswanPlugin; - -typedef struct { - NMVPNPluginClass parent; -} NMStrongswanPluginClass; - -GType nm_strongswan_plugin_get_type(void); - -NMStrongswanPlugin *nm_strongswan_plugin_new(nm_creds_t *creds, - nm_handler_t *handler); - -#endif /** NM_SERVICE_H_ @}*/ diff --git a/src/libcharon/plugins/radattr/Makefile.in b/src/libcharon/plugins/radattr/Makefile.in index ecea0df16..32bdad00c 100644 --- a/src/libcharon/plugins/radattr/Makefile.in +++ b/src/libcharon/plugins/radattr/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_radattr_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_radattr_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_radattr_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/radattr/radattr_listener.c b/src/libcharon/plugins/radattr/radattr_listener.c index 94b718a1b..5443800e5 100644 --- a/src/libcharon/plugins/radattr/radattr_listener.c +++ b/src/libcharon/plugins/radattr/radattr_listener.c @@ -172,9 +172,9 @@ static void add_radius_attribute(private_radattr_listener_t *this, METHOD(listener_t, message, bool, private_radattr_listener_t *this, - ike_sa_t *ike_sa, message_t *message, bool incoming) + ike_sa_t *ike_sa, message_t *message, bool incoming, bool plain) { - if (ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN) && + if (plain && ike_sa->supports_extension(ike_sa, EXT_STRONGSWAN) && message->get_exchange_type(message) == IKE_AUTH && message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) { @@ -212,9 +212,9 @@ radattr_listener_t *radattr_listener_create() .destroy = _destroy, }, .dir = lib->settings->get_str(lib->settings, - "charon.plugins.radattr.dir", NULL), + "%s.plugins.radattr.dir", NULL, charon->name), .mid = lib->settings->get_int(lib->settings, - "charon.plugins.radattr.message_id", -1), + "%s.plugins.radattr.message_id", -1, charon->name), ); return &this->public; diff --git a/src/libcharon/plugins/smp/Makefile.in b/src/libcharon/plugins/smp/Makefile.in index 59a560b86..19cb7987b 100644 --- a/src/libcharon/plugins/smp/Makefile.in +++ b/src/libcharon/plugins/smp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_smp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_smp_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_smp_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_smp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 2b830012d..db5295230 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -49,11 +49,6 @@ struct private_smp_t { * XML unix socket fd */ int socket; - - /** - * job accepting stroke messages - */ - callback_job_t *job; }; ENUM(ike_sa_state_lower_names, IKE_CREATED, IKE_DELETING, @@ -168,7 +163,7 @@ static void write_childend(xmlTextWriterPtr writer, child_sa_t *child, bool loca { linked_list_t *list; - xmlTextWriterWriteFormatElement(writer, "spi", "%lx", + xmlTextWriterWriteFormatElement(writer, "spi", "%x", htonl(child->get_spi(child, local))); list = child->get_traffic_selectors(child, local); write_networks(writer, "networks", list); @@ -294,7 +289,7 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write xmlTextWriterStartElement(writer, "configlist"); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { enumerator_t *children; @@ -302,11 +297,6 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write ike_cfg_t *ike_cfg; linked_list_t *list; - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { /* only IKEv2 connections yet */ - continue; - } - /* */ xmlTextWriterStartElement(writer, "peerconfig"); xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); @@ -316,8 +306,10 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write /* */ ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); xmlTextWriterStartElement(writer, "ikeconfig"); - xmlTextWriterWriteElement(writer, "local", ike_cfg->get_my_addr(ike_cfg)); - xmlTextWriterWriteElement(writer, "remote", ike_cfg->get_other_addr(ike_cfg)); + xmlTextWriterWriteElement(writer, "local", + ike_cfg->get_my_addr(ike_cfg, NULL)); + xmlTextWriterWriteElement(writer, "remote", + ike_cfg->get_other_addr(ike_cfg, NULL)); xmlTextWriterEndElement(writer); /* */ @@ -354,7 +346,7 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write * callback which logs to a XML writer */ static bool xml_callback(xmlTextWriterPtr writer, debug_t group, level_t level, - ike_sa_t* ike_sa, char* format, va_list args) + ike_sa_t* ike_sa, char* message) { if (level <= 1) { @@ -363,7 +355,7 @@ static bool xml_callback(xmlTextWriterPtr writer, debug_t group, level_t level, xmlTextWriterWriteFormatAttribute(writer, "level", "%d", level); xmlTextWriterWriteFormatAttribute(writer, "source", "%N", debug_names, group); xmlTextWriterWriteFormatAttribute(writer, "thread", "%u", thread_current_id()); - xmlTextWriterWriteVFormatString(writer, format, args); + xmlTextWriterWriteString(writer, message); xmlTextWriterEndElement(writer); /* */ } @@ -707,7 +699,8 @@ static job_requeue_t dispatch(private_smp_t *this) fdp = malloc_thing(int); *fdp = fd; - job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job); + job = callback_job_create((callback_job_cb_t)process, fdp, free, + (callback_job_cancel_t)return_false); lib->processor->queue_job(lib->processor, (job_t*)job); return JOB_REQUEUE_DIRECT; @@ -722,7 +715,6 @@ METHOD(plugin_t, get_name, char*, METHOD(plugin_t, destroy, void, private_smp_t *this) { - this->job->cancel(this->job); close(this->socket); free(this); } @@ -765,7 +757,8 @@ plugin_t *smp_plugin_create() return NULL; } umask(old); - if (chown(unix_addr.sun_path, charon->uid, charon->gid) != 0) + if (chown(unix_addr.sun_path, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno)); } @@ -778,9 +771,9 @@ plugin_t *smp_plugin_create() return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)dispatch, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public.plugin; } diff --git a/src/libcharon/plugins/socket_default/Makefile.in b/src/libcharon/plugins/socket_default/Makefile.in index 9c4e5e7b4..3919e053a 100644 --- a/src/libcharon/plugins/socket_default/Makefile.in +++ b/src/libcharon/plugins/socket_default/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_socket_default_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_socket_default_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_socket_default_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index 76ca1df42..51432c960 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -22,6 +22,8 @@ #define _XPG4_2 #define __EXTENSIONS__ #endif +/* make sure to use the proper defs on Mac OS X */ +#define __APPLE_USE_RFC_3542 #include "socket_default_socket.h" @@ -38,9 +40,6 @@ #include #include #include -#ifdef __APPLE__ -#include -#endif #include #include @@ -49,18 +48,6 @@ /* Maximum size of a packet */ #define MAX_PACKET 10000 -/* length of non-esp marker */ -#define MARKER_LEN sizeof(u_int32_t) - -/* from linux/udp.h */ -#ifndef UDP_ENCAP -#define UDP_ENCAP 100 -#endif /*UDP_ENCAP*/ - -#ifndef UDP_ENCAP_ESPINUDP -#define UDP_ENCAP_ESPINUDP 2 -#endif /*UDP_ENCAP_ESPINUDP*/ - /* these are not defined on some platforms */ #ifndef SOL_IP #define SOL_IP IPPROTO_IP @@ -68,9 +55,6 @@ #ifndef SOL_IPV6 #define SOL_IPV6 IPPROTO_IPV6 #endif -#ifndef SOL_UDP -#define SOL_UDP IPPROTO_UDP -#endif /* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that * previously defined IPV6_PKTINFO */ @@ -99,22 +83,32 @@ struct private_socket_default_socket_t { socket_default_socket_t public; /** - * IPv4 socket (500) + * Configured port (or random, if initially 0) + */ + u_int16_t port; + + /** + * Configured port for NAT-T (or random, if initially 0) + */ + u_int16_t natt; + + /** + * IPv4 socket (500 or port) */ int ipv4; /** - * IPv4 socket for NATT (4500) + * IPv4 socket for NAT-T (4500 or natt) */ int ipv4_natt; /** - * IPv6 socket (500) + * IPv6 socket (500 or port) */ int ipv6; /** - * IPv6 socket for NATT (4500) + * IPv6 socket for NAT-T (4500 or natt) */ int ipv6_natt; @@ -122,6 +116,11 @@ struct private_socket_default_socket_t { * Maximum packet size to receive */ int max_packet; + + /** + * TRUE if the source address should be set on outbound packets + */ + bool set_source; }; METHOD(socket_t, receiver, status_t, @@ -131,7 +130,7 @@ METHOD(socket_t, receiver, status_t, chunk_t data; packet_t *pkt; host_t *source = NULL, *dest = NULL; - int bytes_read = 0, data_offset; + int bytes_read = 0; bool oldstate; fd_set rfds; @@ -169,22 +168,22 @@ METHOD(socket_t, receiver, status_t, if (FD_ISSET(this->ipv4, &rfds)) { - port = IKEV2_UDP_PORT; + port = this->port; selected = this->ipv4; } if (FD_ISSET(this->ipv4_natt, &rfds)) { - port = IKEV2_NATT_PORT; + port = this->natt; selected = this->ipv4_natt; } if (FD_ISSET(this->ipv6, &rfds)) { - port = IKEV2_UDP_PORT; + port = this->port; selected = this->ipv6; } if (FD_ISSET(this->ipv6_natt, &rfds)) { - port = IKEV2_NATT_PORT; + port = this->natt; selected = this->ipv6_natt; } if (selected) @@ -220,13 +219,6 @@ METHOD(socket_t, receiver, status_t, } DBG3(DBG_NET, "received packet %b", buffer, bytes_read); - if (bytes_read < MARKER_LEN) - { - DBG3(DBG_NET, "received packet too short (%d bytes)", - bytes_read); - return FAILED; - } - /* read ancillary data to get destination address */ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) @@ -295,17 +287,8 @@ METHOD(socket_t, receiver, status_t, pkt->set_source(pkt, source); pkt->set_destination(pkt, dest); DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); - data_offset = 0; - /* remove non esp marker */ - if (dest->get_port(dest) == IKEV2_NATT_PORT) - { - data_offset += MARKER_LEN; - } - /* fill in packet */ - data.len = bytes_read - data_offset; - data.ptr = malloc(data.len); - memcpy(data.ptr, buffer + data_offset, data.len); - pkt->set_data(pkt, data); + data = chunk_create(buffer, bytes_read); + pkt->set_data(pkt, chunk_clone(data)); } else { @@ -322,7 +305,7 @@ METHOD(socket_t, sender, status_t, { int sport, skt, family; ssize_t bytes_sent; - chunk_t data, marked; + chunk_t data; host_t *src, *dst; struct msghdr msg; struct cmsghdr *cmsg; @@ -337,7 +320,7 @@ METHOD(socket_t, sender, status_t, /* send data */ sport = src->get_port(src); family = dst->get_family(dst); - if (sport == IKEV2_UDP_PORT) + if (sport == 0 || sport == this->port) { if (family == AF_INET) { @@ -348,7 +331,7 @@ METHOD(socket_t, sender, status_t, skt = this->ipv6; } } - else if (sport == IKEV2_NATT_PORT) + else if (sport == this->natt) { if (family == AF_INET) { @@ -358,17 +341,6 @@ METHOD(socket_t, sender, status_t, { skt = this->ipv6_natt; } - /* NAT keepalives without marker */ - if (data.len != 1 || data.ptr[0] != 0xFF) - { - /* add non esp marker to packet */ - marked = chunk_alloc(data.len + MARKER_LEN); - memset(marked.ptr, 0, MARKER_LEN); - memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len); - /* let the packet do the clean up for us */ - packet->set_data(packet, marked); - data = marked; - } } else { @@ -385,7 +357,7 @@ METHOD(socket_t, sender, status_t, msg.msg_iovlen = 1; msg.msg_flags = 0; - if (!src->is_anyaddr(src)) + if (this->set_source && !src->is_anyaddr(src)) { if (family == AF_INET) { @@ -448,11 +420,17 @@ METHOD(socket_t, sender, status_t, return SUCCESS; } +METHOD(socket_t, get_port, u_int16_t, + private_socket_default_socket_t *this, bool nat_t) +{ + return nat_t ? this->natt : this->port; +} + /** * open a socket to send and receive packets */ static int open_socket(private_socket_default_socket_t *this, - int family, u_int16_t port) + int family, u_int16_t *port) { int on = TRUE; struct sockaddr_storage addr; @@ -469,7 +447,7 @@ static int open_socket(private_socket_default_socket_t *this, { struct sockaddr_in *sin = (struct sockaddr_in *)&addr; htoun32(&sin->sin_addr.s_addr, INADDR_ANY); - htoun16(&sin->sin_port, port); + htoun16(&sin->sin_port, *port); addrlen = sizeof(struct sockaddr_in); sol = SOL_IP; #ifdef IP_PKTINFO @@ -483,7 +461,7 @@ static int open_socket(private_socket_default_socket_t *this, { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - htoun16(&sin6->sin6_port, port); + htoun16(&sin6->sin6_port, *port); addrlen = sizeof(struct sockaddr_in6); sol = SOL_IPV6; pktinfo = IPV6_RECVPKTINFO; @@ -514,6 +492,32 @@ static int open_socket(private_socket_default_socket_t *this, return 0; } + /* retrieve randomly allocated port if needed */ + if (*port == 0) + { + if (getsockname(skt, (struct sockaddr *)&addr, &addrlen) < 0) + { + DBG1(DBG_NET, "unable to determine port: %s", strerror(errno)); + close(skt); + return 0; + } + switch (family) + { + case AF_INET: + { + struct sockaddr_in *sin = (struct sockaddr_in *)&addr; + *port = untoh16(&sin->sin_port); + break; + } + case AF_INET6: + { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; + *port = untoh16(&sin6->sin6_port); + break; + } + } + } + /* get additional packet info on receive */ if (pktinfo > 0) { @@ -531,17 +535,15 @@ static int open_socket(private_socket_default_socket_t *this, DBG1(DBG_NET, "installing IKE bypass policy failed"); } -#ifndef __APPLE__ + /* enable UDP decapsulation for NAT-T sockets */ + if (port == &this->natt && + !hydra->kernel_interface->enable_udp_decap(hydra->kernel_interface, + skt, family, this->natt)) { - /* enable UDP decapsulation globally, only for one socket needed */ - int type = UDP_ENCAP_ESPINUDP; - if (family == AF_INET && port == IKEV2_NATT_PORT && - setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) - { - DBG1(DBG_NET, "unable to set UDP_ENCAP: %s", strerror(errno)); - } + DBG1(DBG_NET, "enabling UDP decapsulation for %s on port %d failed", + family == AF_INET ? "IPv4" : "IPv6", this->natt); } -#endif + return skt; } @@ -579,50 +581,55 @@ socket_default_socket_t *socket_default_socket_create() .socket = { .send = _sender, .receive = _receiver, + .get_port = _get_port, .destroy = _destroy, }, }, + .port = lib->settings->get_int(lib->settings, + "%s.port", CHARON_UDP_PORT, charon->name), + .natt = lib->settings->get_int(lib->settings, + "%s.port_nat_t", CHARON_NATT_PORT, charon->name), .max_packet = lib->settings->get_int(lib->settings, - "charon.max_packet", MAX_PACKET), + "%s.max_packet", MAX_PACKET, charon->name), + .set_source = lib->settings->get_bool(lib->settings, + "%s.plugins.socket-default.set_source", TRUE, + charon->name), ); -#ifdef __APPLE__ + if (this->port && this->port == this->natt) { - int natt_port = IKEV2_NATT_PORT; - if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &natt_port, - sizeof(natt_port)) != 0) - { - DBG1(DBG_NET, "could not set net.inet.ipsec.esp_port to %d: %s", - natt_port, strerror(errno)); - } + DBG1(DBG_NET, "IKE ports can't be equal, will allocate NAT-T " + "port randomly"); + this->natt = 0; } -#endif - this->ipv4 = open_socket(this, AF_INET, IKEV2_UDP_PORT); - if (this->ipv4 == 0) + /* we allocate IPv6 sockets first as that will reserve randomly allocated + * ports also for IPv4 */ + this->ipv6 = open_socket(this, AF_INET6, &this->port); + if (this->ipv6 == 0) { - DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled"); + DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled"); } else { - this->ipv4_natt = open_socket(this, AF_INET, IKEV2_NATT_PORT); - if (this->ipv4_natt == 0) + this->ipv6_natt = open_socket(this, AF_INET6, &this->natt); + if (this->ipv6_natt == 0) { - DBG1(DBG_NET, "could not open IPv4 NAT-T socket"); + DBG1(DBG_NET, "could not open IPv6 NAT-T socket"); } } - this->ipv6 = open_socket(this, AF_INET6, IKEV2_UDP_PORT); - if (this->ipv6 == 0) + this->ipv4 = open_socket(this, AF_INET, &this->port); + if (this->ipv4 == 0) { - DBG1(DBG_NET, "could not open IPv6 socket, IPv6 disabled"); + DBG1(DBG_NET, "could not open IPv4 socket, IPv4 disabled"); } else { - this->ipv6_natt = open_socket(this, AF_INET6, IKEV2_NATT_PORT); - if (this->ipv6_natt == 0) + this->ipv4_natt = open_socket(this, AF_INET, &this->natt); + if (this->ipv4_natt == 0) { - DBG1(DBG_NET, "could not open IPv6 NAT-T socket"); + DBG1(DBG_NET, "could not open IPv4 NAT-T socket"); } } @@ -632,6 +639,7 @@ socket_default_socket_t *socket_default_socket_create() destroy(this); return NULL; } + return &this->public; } diff --git a/src/libcharon/plugins/socket_dynamic/Makefile.in b/src/libcharon/plugins/socket_dynamic/Makefile.in index f45e3d255..dfde282b2 100644 --- a/src/libcharon/plugins/socket_dynamic/Makefile.in +++ b/src/libcharon/plugins/socket_dynamic/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_socket_dynamic_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_socket_dynamic_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_socket_dynamic_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c index eee3814a8..33f16cc45 100644 --- a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c +++ b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2010 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -45,18 +45,6 @@ /* Maximum size of a packet */ #define MAX_PACKET 10000 -/* length of non-esp marker */ -#define MARKER_LEN sizeof(u_int32_t) - -/* from linux/udp.h */ -#ifndef UDP_ENCAP -#define UDP_ENCAP 100 -#endif /*UDP_ENCAP*/ - -#ifndef UDP_ENCAP_ESPINUDP -#define UDP_ENCAP_ESPINUDP 2 -#endif /*UDP_ENCAP_ESPINUDP*/ - /* these are not defined on some platforms */ #ifndef SOL_IP #define SOL_IP IPPROTO_IP @@ -64,9 +52,6 @@ #ifndef SOL_IPV6 #define SOL_IPV6 IPPROTO_IPV6 #endif -#ifndef SOL_UDP -#define SOL_UDP IPPROTO_UDP -#endif /* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that * previously defined IPV6_PKTINFO */ @@ -237,12 +222,6 @@ static packet_t *receive_packet(private_socket_dynamic_socket_t *this, } DBG3(DBG_NET, "received packet %b", buffer, (u_int)len); - if (len < MARKER_LEN) - { - DBG3(DBG_NET, "received packet too short (%d bytes)", len); - return NULL; - } - /* read ancillary data to get destination address */ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) @@ -297,12 +276,6 @@ static packet_t *receive_packet(private_socket_dynamic_socket_t *this, packet = packet_create(); packet->set_source(packet, source); packet->set_destination(packet, dest); - /* we assume a non-ESP marker if none of the ports is on 500 */ - if (dest->get_port(dest) != IKEV2_UDP_PORT && - source->get_port(source) != IKEV2_UDP_PORT) - { - data = chunk_skip(data, MARKER_LEN); - } packet->set_data(packet, chunk_clone(data)); return packet; } @@ -358,7 +331,7 @@ METHOD(socket_t, receiver, status_t, static int open_socket(private_socket_dynamic_socket_t *this, int family, u_int16_t port) { - int on = TRUE, type = UDP_ENCAP_ESPINUDP; + int on = TRUE; struct sockaddr_storage addr; socklen_t addrlen; u_int sol, pktinfo = 0; @@ -430,10 +403,13 @@ static int open_socket(private_socket_dynamic_socket_t *this, } /* enable UDP decapsulation on each socket */ - if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) + if (!hydra->kernel_interface->enable_udp_decap(hydra->kernel_interface, + fd, family, port)) { - DBG1(DBG_NET, "unable to set UDP_ENCAP: %s", strerror(errno)); + DBG1(DBG_NET, "enabling UDP decapsulation for %s on port %d failed", + family == AF_INET ? "IPv4" : "IPv6", port); } + return fd; } @@ -483,7 +459,7 @@ METHOD(socket_t, sender, status_t, host_t *src, *dst; int port, family; ssize_t len; - chunk_t data, marked; + chunk_t data; struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; @@ -492,6 +468,7 @@ METHOD(socket_t, sender, status_t, dst = packet->get_destination(packet); family = src->get_family(src); port = src->get_port(src); + port = port ?: CHARON_UDP_PORT; skt = find_socket(this, family, port); if (!skt) { @@ -501,19 +478,6 @@ METHOD(socket_t, sender, status_t, data = packet->get_data(packet); DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst); - /* use non-ESP marker if none of the ports is 500, not for keep alives */ - if (port != IKEV2_UDP_PORT && dst->get_port(dst) != IKEV2_UDP_PORT && - !(data.len == 1 && data.ptr[0] == 0xFF)) - { - /* add non esp marker to packet */ - marked = chunk_alloc(data.len + MARKER_LEN); - memset(marked.ptr, 0, MARKER_LEN); - memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len); - /* let the packet do the clean up for us */ - packet->set_data(packet, marked); - data = marked; - } - memset(&msg, 0, sizeof(struct msghdr)); msg.msg_name = dst->get_sockaddr(dst);; msg.msg_namelen = *dst->get_sockaddr_len(dst); @@ -572,6 +536,14 @@ METHOD(socket_t, sender, status_t, return SUCCESS; } +METHOD(socket_t, get_port, u_int16_t, + private_socket_dynamic_socket_t *this, bool nat_t) +{ + /* we return 0 here for users that have no explicit port configured, the + * sender will default to the default port in this case */ + return 0; +} + METHOD(socket_t, destroy, void, private_socket_dynamic_socket_t *this) { @@ -605,12 +577,13 @@ socket_dynamic_socket_t *socket_dynamic_socket_create() .socket = { .send = _sender, .receive = _receiver, + .get_port = _get_port, .destroy = _destroy, }, }, .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .max_packet = lib->settings->get_int(lib->settings, - "charon.max_packet", MAX_PACKET), + "%s.max_packet", MAX_PACKET, charon->name), ); if (pipe(this->notify) != 0) diff --git a/src/libcharon/plugins/socket_raw/Makefile.am b/src/libcharon/plugins/socket_raw/Makefile.am deleted file mode 100644 index 2109ae5f3..000000000 --- a/src/libcharon/plugins/socket_raw/Makefile.am +++ /dev/null @@ -1,17 +0,0 @@ - -INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan \ - -I$(top_srcdir)/src/libhydra -I$(top_srcdir)/src/libcharon - -AM_CFLAGS = -rdynamic - -if MONOLITHIC -noinst_LTLIBRARIES = libstrongswan-socket-raw.la -else -plugin_LTLIBRARIES = libstrongswan-socket-raw.la -endif - -libstrongswan_socket_raw_la_SOURCES = \ - socket_raw_plugin.h socket_raw_plugin.c \ - socket_raw_socket.h socket_raw_socket.c - -libstrongswan_socket_raw_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/socket_raw/Makefile.in b/src/libcharon/plugins/socket_raw/Makefile.in deleted file mode 100644 index 5abceb6c3..000000000 --- a/src/libcharon/plugins/socket_raw/Makefile.in +++ /dev/null @@ -1,616 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/libcharon/plugins/socket_raw -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(plugindir)" -LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) -libstrongswan_socket_raw_la_LIBADD = -am_libstrongswan_socket_raw_la_OBJECTS = socket_raw_plugin.lo \ - socket_raw_socket.lo -libstrongswan_socket_raw_la_OBJECTS = \ - $(am_libstrongswan_socket_raw_la_OBJECTS) -libstrongswan_socket_raw_la_LINK = $(LIBTOOL) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_socket_raw_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -@MONOLITHIC_FALSE@am_libstrongswan_socket_raw_la_rpath = -rpath \ -@MONOLITHIC_FALSE@ $(plugindir) -@MONOLITHIC_TRUE@am_libstrongswan_socket_raw_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libstrongswan_socket_raw_la_SOURCES) -DIST_SOURCES = $(libstrongswan_socket_raw_la_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -INCLUDES = -I${linux_headers} -I$(top_srcdir)/src/libstrongswan \ - -I$(top_srcdir)/src/libhydra -I$(top_srcdir)/src/libcharon - -AM_CFLAGS = -rdynamic -@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-socket-raw.la -@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-socket-raw.la -libstrongswan_socket_raw_la_SOURCES = \ - socket_raw_plugin.h socket_raw_plugin.c \ - socket_raw_socket.h socket_raw_socket.c - -libstrongswan_socket_raw_la_LDFLAGS = -module -avoid-version -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/socket_raw/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/libcharon/plugins/socket_raw/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ - } - -uninstall-pluginLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ - done - -clean-pluginLTLIBRARIES: - -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libstrongswan-socket-raw.la: $(libstrongswan_socket_raw_la_OBJECTS) $(libstrongswan_socket_raw_la_DEPENDENCIES) - $(libstrongswan_socket_raw_la_LINK) $(am_libstrongswan_socket_raw_la_rpath) $(libstrongswan_socket_raw_la_OBJECTS) $(libstrongswan_socket_raw_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_raw_plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket_raw_socket.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(plugindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ - clean-pluginLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pluginLTLIBRARIES - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pluginLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ - ctags distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-pluginLTLIBRARIES install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags uninstall uninstall-am \ - uninstall-pluginLTLIBRARIES - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/libcharon/plugins/socket_raw/socket_raw_plugin.c b/src/libcharon/plugins/socket_raw/socket_raw_plugin.c deleted file mode 100644 index 1299c30ca..000000000 --- a/src/libcharon/plugins/socket_raw/socket_raw_plugin.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "socket_raw_plugin.h" - -#include "socket_raw_socket.h" - -#include - -typedef struct private_socket_raw_plugin_t private_socket_raw_plugin_t; - -/** - * Private data of socket plugin - */ -struct private_socket_raw_plugin_t { - - /** - * Implements plugin interface - */ - socket_raw_plugin_t public; -}; - -METHOD(plugin_t, get_name, char*, - private_socket_raw_plugin_t *this) -{ - return "socket-raw"; -} - -METHOD(plugin_t, get_features, int, - private_socket_raw_plugin_t *this, plugin_feature_t *features[]) -{ - static plugin_feature_t f[] = { - PLUGIN_CALLBACK(socket_register, socket_raw_socket_create), - PLUGIN_PROVIDE(CUSTOM, "socket"), - }; - *features = f; - return countof(f); -} - -METHOD(plugin_t, destroy, void, - private_socket_raw_plugin_t *this) -{ - free(this); -} - -/* - * see header file - */ -plugin_t *socket_raw_plugin_create() -{ - private_socket_raw_plugin_t *this; - - INIT(this, - .public = { - .plugin = { - .get_name = _get_name, - .get_features = _get_features, - .destroy = _destroy, - }, - }, - ); - - return &this->public.plugin; -} - diff --git a/src/libcharon/plugins/socket_raw/socket_raw_plugin.h b/src/libcharon/plugins/socket_raw/socket_raw_plugin.h deleted file mode 100644 index a692b7594..000000000 --- a/src/libcharon/plugins/socket_raw/socket_raw_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup socket_raw socket_raw - * @ingroup cplugins - * - * @defgroup socket_raw_plugin socket_raw_plugin - * @{ @ingroup socket_raw - */ - -#ifndef SOCKET_RAW_PLUGIN_H_ -#define SOCKET_RAW_PLUGIN_H_ - -#include - -typedef struct socket_raw_plugin_t socket_raw_plugin_t; - -/** - * RAW socket implementation plugin. - */ -struct socket_raw_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** SOCKET_RAW_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/socket_raw/socket_raw_socket.c b/src/libcharon/plugins/socket_raw/socket_raw_socket.c deleted file mode 100644 index ae37d8f2b..000000000 --- a/src/libcharon/plugins/socket_raw/socket_raw_socket.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * Copyright (C) 2006-2010 Tobias Brunner - * Copyright (C) 2005-2010 Martin Willi - * Copyright (C) 2006 Daniel Roethlisberger - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* for struct in6_pktinfo */ -#define _GNU_SOURCE - -#include "socket_raw_socket.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Maximum size of a packet */ -#define MAX_PACKET 10000 - -/* constants for packet handling */ -#define IP_LEN sizeof(struct iphdr) -#define IP6_LEN sizeof(struct ip6_hdr) -#define UDP_LEN sizeof(struct udphdr) -#define MARKER_LEN sizeof(u_int32_t) - -/* offsets for packet handling */ -#define IP_PROTO_OFFSET 9 -#define IP6_PROTO_OFFSET 6 -#define IKE_VERSION_OFFSET 17 -#define IKE_LENGTH_OFFSET 24 - -/* from linux/udp.h */ -#ifndef UDP_ENCAP -#define UDP_ENCAP 100 -#endif /*UDP_ENCAP*/ - -#ifndef UDP_ENCAP_ESPINUDP -#define UDP_ENCAP_ESPINUDP 2 -#endif /*UDP_ENCAP_ESPINUDP*/ - -/* needed for older kernel headers */ -#ifndef IPV6_2292PKTINFO -#define IPV6_2292PKTINFO 2 -#endif /*IPV6_2292PKTINFO*/ - -typedef struct private_socket_raw_socket_t private_socket_raw_socket_t; - -/** - * Private data of an socket_t object - */ -struct private_socket_raw_socket_t { - - /** - * public functions - */ - socket_raw_socket_t public; - - /** - * regular port - */ - int port; - - /** - * port used for nat-t - */ - int natt_port; - - /** - * raw receiver socket for IPv4 - */ - int recv4; - - /** - * raw receiver socket for IPv6 - */ - int recv6; - - /** - * send socket on regular port for IPv4 - */ - int send4; - - /** - * send socket on regular port for IPv6 - */ - int send6; - - /** - * send socket on nat-t port for IPv4 - */ - int send4_natt; - - /** - * send socket on nat-t port for IPv6 - */ - int send6_natt; - - /** - * Maximum packet size to receive - */ - int max_packet; -}; - -METHOD(socket_t, receiver, status_t, - private_socket_raw_socket_t *this, packet_t **packet) -{ - char buffer[this->max_packet]; - chunk_t data; - packet_t *pkt; - struct udphdr *udp; - host_t *source = NULL, *dest = NULL; - int bytes_read = 0, data_offset; - bool oldstate; - fd_set rfds; - - FD_ZERO(&rfds); - - if (this->recv4) - { - FD_SET(this->recv4, &rfds); - } - if (this->recv6) - { - FD_SET(this->recv6, &rfds); - } - - DBG2(DBG_NET, "waiting for data on raw sockets"); - - oldstate = thread_cancelability(TRUE); - if (select(max(this->recv4, this->recv6) + 1, &rfds, NULL, NULL, NULL) <= 0) - { - thread_cancelability(oldstate); - return FAILED; - } - thread_cancelability(oldstate); - - if (this->recv4 && FD_ISSET(this->recv4, &rfds)) - { - /* IPv4 raw sockets return the IP header. We read src/dest - * information directly from the raw header */ - struct iphdr *ip; - struct sockaddr_in src, dst; - - bytes_read = recv(this->recv4, buffer, this->max_packet, 0); - if (bytes_read < 0) - { - DBG1(DBG_NET, "error reading from IPv4 socket: %s", strerror(errno)); - return FAILED; - } - if (bytes_read == this->max_packet) - { - DBG1(DBG_NET, "receive buffer too small, packet discarded"); - return FAILED; - } - DBG3(DBG_NET, "received IPv4 packet %b", buffer, bytes_read); - - /* read source/dest from raw IP/UDP header */ - if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) - { - DBG1(DBG_NET, "received IPv4 packet too short (%d bytes)", - bytes_read); - return FAILED; - } - ip = (struct iphdr*) buffer; - udp = (struct udphdr*) (buffer + IP_LEN); - src.sin_family = AF_INET; - src.sin_addr.s_addr = ip->saddr; - src.sin_port = udp->source; - dst.sin_family = AF_INET; - dst.sin_addr.s_addr = ip->daddr; - dst.sin_port = udp->dest; - source = host_create_from_sockaddr((sockaddr_t*)&src); - dest = host_create_from_sockaddr((sockaddr_t*)&dst); - - pkt = packet_create(); - pkt->set_source(pkt, source); - pkt->set_destination(pkt, dest); - DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); - data_offset = IP_LEN + UDP_LEN; - /* remove non esp marker */ - if (dest->get_port(dest) == IKEV2_NATT_PORT) - { - data_offset += MARKER_LEN; - } - /* fill in packet */ - data.len = bytes_read - data_offset; - data.ptr = malloc(data.len); - memcpy(data.ptr, buffer + data_offset, data.len); - pkt->set_data(pkt, data); - } - else if (this->recv6 && FD_ISSET(this->recv6, &rfds)) - { - /* IPv6 raw sockets return no IP header. We must query - * src/dest via socket options/ancillary data */ - struct msghdr msg; - struct cmsghdr *cmsgptr; - struct sockaddr_in6 src, dst; - struct iovec iov; - char ancillary[64]; - - msg.msg_name = &src; - msg.msg_namelen = sizeof(src); - iov.iov_base = buffer; - iov.iov_len = this->max_packet; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = ancillary; - msg.msg_controllen = sizeof(ancillary); - msg.msg_flags = 0; - - bytes_read = recvmsg(this->recv6, &msg, 0); - if (bytes_read < 0) - { - DBG1(DBG_NET, "error reading from IPv6 socket: %s", strerror(errno)); - return FAILED; - } - DBG3(DBG_NET, "received IPv6 packet %b", buffer, bytes_read); - - if (bytes_read < IP_LEN + UDP_LEN + MARKER_LEN) - { - DBG3(DBG_NET, "received IPv6 packet too short (%d bytes)", - bytes_read); - return FAILED; - } - - /* read ancillary data to get destination address */ - for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; - cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) - { - if (cmsgptr->cmsg_len == 0) - { - DBG1(DBG_NET, "error reading IPv6 ancillary data"); - return FAILED; - } - -#ifdef HAVE_IN6_PKTINFO - if (cmsgptr->cmsg_level == SOL_IPV6 && - cmsgptr->cmsg_type == IPV6_2292PKTINFO) - { - struct in6_pktinfo *pktinfo; - pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsgptr); - - memset(&dst, 0, sizeof(dst)); - memcpy(&dst.sin6_addr, &pktinfo->ipi6_addr, sizeof(dst.sin6_addr)); - dst.sin6_family = AF_INET6; - udp = (struct udphdr*) (buffer); - dst.sin6_port = udp->dest; - src.sin6_port = udp->source; - dest = host_create_from_sockaddr((sockaddr_t*)&dst); - } -#endif /* HAVE_IN6_PKTINFO */ - } - /* ancillary data missing? */ - if (dest == NULL) - { - DBG1(DBG_NET, "error reading IPv6 packet header"); - return FAILED; - } - - source = host_create_from_sockaddr((sockaddr_t*)&src); - - pkt = packet_create(); - pkt->set_source(pkt, source); - pkt->set_destination(pkt, dest); - DBG2(DBG_NET, "received packet: from %#H to %#H", source, dest); - data_offset = UDP_LEN; - /* remove non esp marker */ - if (dest->get_port(dest) == IKEV2_NATT_PORT) - { - data_offset += MARKER_LEN; - } - /* fill in packet */ - data.len = bytes_read - data_offset; - data.ptr = malloc(data.len); - memcpy(data.ptr, buffer + data_offset, data.len); - pkt->set_data(pkt, data); - } - else - { - /* oops, shouldn't happen */ - return FAILED; - } - - /* return packet */ - *packet = pkt; - return SUCCESS; -} - -METHOD(socket_t, sender, status_t, - private_socket_raw_socket_t *this, packet_t *packet) -{ - int sport, skt, family; - ssize_t bytes_sent; - chunk_t data, marked; - host_t *src, *dst; - struct msghdr msg; - struct cmsghdr *cmsg; - struct iovec iov; - - src = packet->get_source(packet); - dst = packet->get_destination(packet); - data = packet->get_data(packet); - - DBG2(DBG_NET, "sending packet: from %#H to %#H", src, dst); - - /* send data */ - sport = src->get_port(src); - family = dst->get_family(dst); - if (sport == IKEV2_UDP_PORT) - { - if (family == AF_INET) - { - skt = this->send4; - } - else - { - skt = this->send6; - } - } - else if (sport == IKEV2_NATT_PORT) - { - if (family == AF_INET) - { - skt = this->send4_natt; - } - else - { - skt = this->send6_natt; - } - /* NAT keepalives without marker */ - if (data.len != 1 || data.ptr[0] != 0xFF) - { - /* add non esp marker to packet */ - marked = chunk_alloc(data.len + MARKER_LEN); - memset(marked.ptr, 0, MARKER_LEN); - memcpy(marked.ptr + MARKER_LEN, data.ptr, data.len); - /* let the packet do the clean up for us */ - packet->set_data(packet, marked); - data = marked; - } - } - else - { - DBG1(DBG_NET, "unable to locate a send socket for port %d", sport); - return FAILED; - } - - memset(&msg, 0, sizeof(struct msghdr)); - msg.msg_name = dst->get_sockaddr(dst);; - msg.msg_namelen = *dst->get_sockaddr_len(dst); - iov.iov_base = data.ptr; - iov.iov_len = data.len; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - - if (!src->is_anyaddr(src)) - { - if (family == AF_INET) - { - char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct in_pktinfo *pktinfo; - struct sockaddr_in *sin; - - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in_pktinfo)); - sin = (struct sockaddr_in*)src->get_sockaddr(src); - memcpy(&pktinfo->ipi_spec_dst, &sin->sin_addr, sizeof(struct in_addr)); - } -#ifdef HAVE_IN6_PKTINFO - else - { - char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct in6_pktinfo *pktinfo; - struct sockaddr_in6 *sin; - - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_IPV6; - cmsg->cmsg_type = IPV6_2292PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); - memset(pktinfo, 0, sizeof(struct in6_pktinfo)); - sin = (struct sockaddr_in6*)src->get_sockaddr(src); - memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr)); - } -#endif /* HAVE_IN6_PKTINFO */ - } - - bytes_sent = sendmsg(skt, &msg, 0); - - if (bytes_sent != data.len) - { - DBG1(DBG_NET, "error writing to socket: %s", strerror(errno)); - return FAILED; - } - return SUCCESS; -} - -/** - * open a socket to send packets - */ -static int open_send_socket(private_socket_raw_socket_t *this, - int family, u_int16_t port) -{ - int on = TRUE; - int type = UDP_ENCAP_ESPINUDP; - struct sockaddr_storage addr; - int skt; - - memset(&addr, 0, sizeof(addr)); - addr.ss_family = family; - /* precalculate constants depending on address family */ - switch (family) - { - case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)&addr; - htoun32(&sin->sin_addr.s_addr, INADDR_ANY); - htoun16(&sin->sin_port, port); - break; - } - case AF_INET6: - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; - memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - htoun16(&sin6->sin6_port, port); - break; - } - default: - return 0; - } - - skt = socket(family, SOCK_DGRAM, IPPROTO_UDP); - if (skt < 0) - { - DBG1(DBG_NET, "could not open send socket: %s", strerror(errno)); - return 0; - } - - if (setsockopt(skt, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)) < 0) - { - DBG1(DBG_NET, "unable to set SO_REUSEADDR on send socket: %s", - strerror(errno)); - close(skt); - return 0; - } - - /* bind the send socket */ - if (bind(skt, (struct sockaddr *)&addr, sizeof(addr)) < 0) - { - DBG1(DBG_NET, "unable to bind send socket: %s", - strerror(errno)); - close(skt); - return 0; - } - - if (family == AF_INET) - { - /* enable UDP decapsulation globally, only for one socket needed */ - if (setsockopt(skt, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) - { - DBG1(DBG_NET, "unable to set UDP_ENCAP: %s; NAT-T may fail", - strerror(errno)); - } - } - - if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface, - skt, family)) - { - DBG1(DBG_NET, "installing bypass policy on send socket failed"); - } - - return skt; -} - -/** - * open a socket to receive packets - */ -static int open_recv_socket(private_socket_raw_socket_t *this, int family) -{ - int skt; - int on = TRUE; - u_int ip_len, sol, udp_header, ike_header; - - /* precalculate constants depending on address family */ - switch (family) - { - case AF_INET: - ip_len = IP_LEN; - sol = SOL_IP; - break; - case AF_INET6: - ip_len = 0; /* IPv6 raw sockets contain no IP header */ - sol = SOL_IPV6; - break; - default: - return 0; - } - udp_header = ip_len; - ike_header = ip_len + UDP_LEN; - - /* This filter code filters out all non-IKEv2 traffic on - * a SOCK_RAW IP_PROTP_UDP socket. Handling of other - * IKE versions is done in pluto. - */ - struct sock_filter ikev2_filter_code[] = - { - /* Destination Port must be either port or natt_port */ - BPF_STMT(BPF_LD+BPF_H+BPF_ABS, udp_header + 2), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_UDP_PORT, 1, 0), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IKEV2_NATT_PORT, 6, 14), - /* port */ - /* IKE version must be 2.x */ - BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + IKE_VERSION_OFFSET), - BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 4), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 2, 0, 11), - /* packet length is length in IKEv2 header + ip header + udp header */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + IKE_LENGTH_OFFSET), - BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN), - BPF_STMT(BPF_RET+BPF_A, 0), - /* natt_port */ - /* nat-t: check for marker */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 6), - /* nat-t: IKE version must be 2.x */ - BPF_STMT(BPF_LD+BPF_B+BPF_ABS, ike_header + MARKER_LEN + IKE_VERSION_OFFSET), - BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 4), - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 2, 0, 3), - /* nat-t: packet length is length in IKEv2 header + ip header + udp header + non esp marker */ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ike_header + MARKER_LEN + IKE_LENGTH_OFFSET), - BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, ip_len + UDP_LEN + MARKER_LEN), - BPF_STMT(BPF_RET+BPF_A, 0), - /* packet doesn't match, ignore */ - BPF_STMT(BPF_RET+BPF_K, 0), - }; - - /* Filter struct to use with setsockopt */ - struct sock_fprog ikev2_filter = { - sizeof(ikev2_filter_code) / sizeof(struct sock_filter), - ikev2_filter_code - }; - - /* set up a raw socket */ - skt = socket(family, SOCK_RAW, IPPROTO_UDP); - if (skt < 0) - { - DBG1(DBG_NET, "unable to create raw socket: %s", strerror(errno)); - return 0; - } - - if (setsockopt(skt, SOL_SOCKET, SO_ATTACH_FILTER, - &ikev2_filter, sizeof(ikev2_filter)) < 0) - { - DBG1(DBG_NET, "unable to attach IKEv2 filter to raw socket: %s", - strerror(errno)); - close(skt); - return 0; - } - - if (family == AF_INET6 && - /* we use IPV6_2292PKTINFO, as IPV6_PKTINFO is defined as - * 2 or 50 depending on kernel header version */ - setsockopt(skt, sol, IPV6_2292PKTINFO, &on, sizeof(on)) < 0) - { - DBG1(DBG_NET, "unable to set IPV6_PKTINFO on raw socket: %s", - strerror(errno)); - close(skt); - return 0; - } - - if (!hydra->kernel_interface->bypass_socket(hydra->kernel_interface, - skt, family)) - { - DBG1(DBG_NET, "installing bypass policy on receive socket failed"); - } - - return skt; -} - -METHOD(socket_t, destroy, void, - private_socket_raw_socket_t *this) -{ - if (this->recv4) - { - close(this->recv4); - } - if (this->recv6) - { - close(this->recv6); - } - if (this->send4) - { - close(this->send4); - } - if (this->send6) - { - close(this->send6); - } - if (this->send4_natt) - { - close(this->send4_natt); - } - if (this->send6_natt) - { - close(this->send6_natt); - } - free(this); -} - -/* - * See header for description - */ -socket_raw_socket_t *socket_raw_socket_create() -{ - private_socket_raw_socket_t *this; - - INIT(this, - .public = { - .socket = { - .send = _sender, - .receive = _receiver, - .destroy = _destroy, - }, - }, - .max_packet = lib->settings->get_int(lib->settings, - "charon.max_packet", MAX_PACKET), - ); - - this->recv4 = open_recv_socket(this, AF_INET); - if (this->recv4 == 0) - { - DBG1(DBG_NET, "could not open IPv4 receive socket, IPv4 disabled"); - } - else - { - this->send4 = open_send_socket(this, AF_INET, IKEV2_UDP_PORT); - if (this->send4 == 0) - { - DBG1(DBG_NET, "could not open IPv4 send socket, IPv4 disabled"); - close(this->recv4); - } - else - { - this->send4_natt = open_send_socket(this, AF_INET, IKEV2_NATT_PORT); - if (this->send4_natt == 0) - { - DBG1(DBG_NET, "could not open IPv4 NAT-T send socket"); - } - } - } - - this->recv6 = open_recv_socket(this, AF_INET6); - if (this->recv6 == 0) - { - DBG1(DBG_NET, "could not open IPv6 receive socket, IPv6 disabled"); - } - else - { - this->send6 = open_send_socket(this, AF_INET6, IKEV2_UDP_PORT); - if (this->send6 == 0) - { - DBG1(DBG_NET, "could not open IPv6 send socket, IPv6 disabled"); - close(this->recv6); - } - else - { - this->send6_natt = open_send_socket(this, AF_INET6, IKEV2_NATT_PORT); - if (this->send6_natt == 0) - { - DBG1(DBG_NET, "could not open IPv6 NAT-T send socket"); - } - } - } - - if (!(this->send4 || this->send6) || !(this->recv4 || this->recv6)) - { - DBG1(DBG_NET, "could not create any sockets"); - destroy(this); - return NULL; - } - - return &this->public; -} diff --git a/src/libcharon/plugins/socket_raw/socket_raw_socket.h b/src/libcharon/plugins/socket_raw/socket_raw_socket.h deleted file mode 100644 index 23ff304a8..000000000 --- a/src/libcharon/plugins/socket_raw/socket_raw_socket.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup socket_raw_socket socket_raw_socket - * @{ @ingroup socket_raw - */ - -#ifndef SOCKET_RAW_SOCKET_H_ -#define SOCKET_RAW_SOCKET_H_ - -typedef struct socket_raw_socket_t socket_raw_socket_t; - -#include - -/** - * Raw socket, binds to port 500/4500 using any IPv4/IPv6 address. - * - * This imeplementation uses raw sockets to allow binding of other daemons - * (pluto) to UDP/500/4500. An installed "Linux socket filter" filters out - * all non-IKEv2 traffic and handles just IKEv2 messages. An other daemon - * must handle all traffic separately, e.g. ignore IKEv2 traffic, since charon - * handles that. - */ -struct socket_raw_socket_t { - - /** - * Implements the socket_t interface. - */ - socket_t socket; - -}; - -/** - * Create a socket_raw_socket instance. - */ -socket_raw_socket_t *socket_raw_socket_create(); - -#endif /** SOCKET_RAW_SOCKET_H_ @}*/ diff --git a/src/libcharon/plugins/sql/Makefile.in b/src/libcharon/plugins/sql/Makefile.in index d04c7f6c9..a6c6cbe1e 100644 --- a/src/libcharon/plugins/sql/Makefile.in +++ b/src/libcharon/plugins/sql/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_sql_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_sql_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_sql_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_sql_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index dc016012c..c614c679e 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -259,7 +259,8 @@ static ike_cfg_t *build_ike_cfg(private_sql_config_t *this, enumerator_t *e, ike_cfg_t *ike_cfg; ike_cfg = ike_cfg_create(certreq, force_encap, - local, IKEV2_UDP_PORT, remote, IKEV2_UDP_PORT); + local, FALSE, charon->socket->get_port(charon->socket, FALSE), + remote, FALSE, IKEV2_UDP_PORT); add_ike_proposals(this, ike_cfg, id); return ike_cfg; } @@ -332,6 +333,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, mediation, mediated_by, p_type; chunk_t l_data, r_data, p_data; char *name, *virtual, *pool; + enumerator_t *enumerator; while (e->enumerate(e, &id, &name, &ike_cfg, &l_type, &l_data, &r_type, &r_data, @@ -368,10 +370,25 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, if (ike) { peer_cfg = peer_cfg_create( - name, 2, ike, cert_policy, uniqueid, + name, IKEV2, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, - mobike, dpd_delay, vip, pool, + mobike, FALSE, dpd_delay, 0, mediation, mediated_cfg, peer_id); + if (vip) + { + peer_cfg->add_virtual_ip(peer_cfg, vip); + } + if (pool) + { + /* attr-sql used comma separated pools, but we now completely + * support multiple pools directly. Support old SQL configs: */ + enumerator = enumerator_create_token(pool, ",", " "); + while (enumerator->enumerate(enumerator, &pool)) + { + peer_cfg->add_pool(peer_cfg, pool); + } + enumerator->destroy(enumerator); + } auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method); auth->add(auth, AUTH_RULE_IDENTITY, local_id); diff --git a/src/libcharon/plugins/sql/sql_logger.c b/src/libcharon/plugins/sql/sql_logger.c index 10ceacb00..6db3258d2 100644 --- a/src/libcharon/plugins/sql/sql_logger.c +++ b/src/libcharon/plugins/sql/sql_logger.c @@ -18,6 +18,7 @@ #include "sql_logger.h" #include +#include typedef struct private_sql_logger_t private_sql_logger_t; @@ -42,24 +43,23 @@ struct private_sql_logger_t { int level; /** - * avoid recursive logging + * avoid recursive calls by the same thread */ - bool recursive; + thread_value_t *recursive; }; -METHOD(listener_t, log_, bool, +METHOD(logger_t, log_, void, private_sql_logger_t *this, debug_t group, level_t level, int thread, - ike_sa_t* ike_sa, char *format, va_list args) + ike_sa_t* ike_sa, const char *message) { - if (this->recursive) + if (this->recursive->get(this->recursive)) { - return TRUE; + return; } - this->recursive = TRUE; + this->recursive->set(this->recursive, this->recursive); - if (ike_sa && level <= this->level) + if (ike_sa) { - char buffer[8192]; chunk_t local_spi, remote_spi; host_t *local_host, *remote_host; identification_t *local_id, *remote_id; @@ -85,8 +85,6 @@ METHOD(listener_t, log_, bool, local_host = ike_sa->get_my_host(ike_sa); remote_host = ike_sa->get_other_host(ike_sa); - vsnprintf(buffer, sizeof(buffer), format, args); - this->db->execute(this->db, NULL, "REPLACE INTO ike_sas (" "local_spi, remote_spi, id, initiator, " "local_id_type, local_id_data, " @@ -106,11 +104,16 @@ METHOD(listener_t, log_, bool, this->db->execute(this->db, NULL, "INSERT INTO logs (" "local_spi, signal, level, msg) VALUES (?, ?, ?, ?)", DB_BLOB, local_spi, DB_INT, group, DB_INT, level, - DB_TEXT, buffer); + DB_TEXT, message); } - this->recursive = FALSE; - /* always stay registered */ - return TRUE; + + this->recursive->set(this->recursive, NULL); +} + +METHOD(logger_t, get_level, level_t, + private_sql_logger_t *this, debug_t group) +{ + return this->level; } METHOD(sql_logger_t, destroy, void, @@ -128,14 +131,16 @@ sql_logger_t *sql_logger_create(database_t *db) INIT(this, .public = { - .listener = { + .logger = { .log = _log_, + .get_level = _get_level, }, .destroy = _destroy, }, .db = db, + .recursive = thread_value_create(NULL), .level = lib->settings->get_int(lib->settings, - "charon.plugins.sql.loglevel", -1), + "%s.plugins.sql.loglevel", -1, charon->name), ); return &this->public; diff --git a/src/libcharon/plugins/sql/sql_logger.h b/src/libcharon/plugins/sql/sql_logger.h index a933705da..62dc3f361 100644 --- a/src/libcharon/plugins/sql/sql_logger.h +++ b/src/libcharon/plugins/sql/sql_logger.h @@ -32,9 +32,9 @@ typedef struct sql_logger_t sql_logger_t; struct sql_logger_t { /** - * Implements bus_listener_t interface + * Implements logger_t interface */ - listener_t listener; + logger_t logger; /** * Destry the backend. diff --git a/src/libcharon/plugins/sql/sql_plugin.c b/src/libcharon/plugins/sql/sql_plugin.c index d915d4696..afbb89c83 100644 --- a/src/libcharon/plugins/sql/sql_plugin.c +++ b/src/libcharon/plugins/sql/sql_plugin.c @@ -64,7 +64,7 @@ METHOD(plugin_t, destroy, void, { charon->backends->remove_backend(charon->backends, &this->config->backend); lib->credmgr->remove_set(lib->credmgr, &this->cred->set); - charon->bus->remove_listener(charon->bus, &this->logger->listener); + charon->bus->remove_logger(charon->bus, &this->logger->logger); this->config->destroy(this->config); this->cred->destroy(this->cred); this->logger->destroy(this->logger); @@ -80,7 +80,8 @@ plugin_t *sql_plugin_create() char *uri; private_sql_plugin_t *this; - uri = lib->settings->get_str(lib->settings, "charon.plugins.sql.database", NULL); + uri = lib->settings->get_str(lib->settings, "%s.plugins.sql.database", + NULL, charon->name); if (!uri) { DBG1(DBG_CFG, "sql plugin: database URI not set"); @@ -110,7 +111,7 @@ plugin_t *sql_plugin_create() charon->backends->add_backend(charon->backends, &this->config->backend); lib->credmgr->add_set(lib->credmgr, &this->cred->set); - charon->bus->add_listener(charon->bus, &this->logger->listener); + charon->bus->add_logger(charon->bus, &this->logger->logger); return &this->public.plugin; } diff --git a/src/libcharon/plugins/stroke/Makefile.am b/src/libcharon/plugins/stroke/Makefile.am index e561224e9..cebcd984f 100644 --- a/src/libcharon/plugins/stroke/Makefile.am +++ b/src/libcharon/plugins/stroke/Makefile.am @@ -21,6 +21,7 @@ libstrongswan_stroke_la_SOURCES = \ stroke_cred.h stroke_cred.c \ stroke_ca.h stroke_ca.c \ stroke_attribute.h stroke_attribute.c \ + stroke_handler.h stroke_handler.c \ stroke_list.h stroke_list.c libstrongswan_stroke_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/stroke/Makefile.in b/src/libcharon/plugins/stroke/Makefile.in index 60f5f535a..f0db20c42 100644 --- a/src/libcharon/plugins/stroke/Makefile.in +++ b/src/libcharon/plugins/stroke/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -77,7 +78,7 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_stroke_la_LIBADD = am_libstrongswan_stroke_la_OBJECTS = stroke_plugin.lo stroke_socket.lo \ stroke_config.lo stroke_control.lo stroke_cred.lo stroke_ca.lo \ - stroke_attribute.lo stroke_list.lo + stroke_attribute.lo stroke_handler.lo stroke_list.lo libstrongswan_stroke_la_OBJECTS = \ $(am_libstrongswan_stroke_la_OBJECTS) libstrongswan_stroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -86,7 +87,7 @@ libstrongswan_stroke_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_stroke_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_stroke_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -302,6 +308,7 @@ libstrongswan_stroke_la_SOURCES = \ stroke_cred.h stroke_cred.c \ stroke_ca.h stroke_ca.c \ stroke_attribute.h stroke_attribute.c \ + stroke_handler.h stroke_handler.c \ stroke_list.h stroke_list.c libstrongswan_stroke_la_LDFLAGS = -module -avoid-version @@ -393,6 +400,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_control.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_cred.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_list.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stroke_socket.Plo@am__quote@ diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c index 1e4615e12..85fb94e9e 100644 --- a/src/libcharon/plugins/stroke/stroke_attribute.c +++ b/src/libcharon/plugins/stroke/stroke_attribute.c @@ -17,7 +17,6 @@ #include "stroke_attribute.h" #include -#include #include #include @@ -38,12 +37,37 @@ struct private_stroke_attribute_t { */ linked_list_t *pools; + /** + * List of connection specific attributes, as attributes_t + */ + linked_list_t *attrs; + /** * rwlock to lock access to pools */ rwlock_t *lock; }; +/** + * Attributes assigned to a connection + */ +typedef struct { + /** name of the connection */ + char *name; + /** list of DNS attributes, as host_t */ + linked_list_t *dns; +} attributes_t; + +/** + * Destroy an attributes_t entry + */ +static void attributes_destroy(attributes_t *this) +{ + this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); + free(this->name); + free(this); +} + /** * find a pool by name */ @@ -65,88 +89,246 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name) return found; } -METHOD(attribute_provider_t, acquire_address, host_t*, - private_stroke_attribute_t *this, char *name, identification_t *id, - host_t *requested) +/** + * Find an existing or not yet existing lease + */ +static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools, + identification_t *id, host_t *requested, + mem_pool_op_t operation) { - mem_pool_t *pool; host_t *addr = NULL; + enumerator_t *enumerator; + mem_pool_t *pool; + char *name; + + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &name)) + { + pool = find_pool(this, name); + if (pool) + { + addr = pool->acquire_address(pool, id, requested, operation); + if (addr) + { + break; + } + } + } + enumerator->destroy(enumerator); + + return addr; +} + +METHOD(attribute_provider_t, acquire_address, host_t*, + private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id, + host_t *requested) +{ + host_t *addr; + this->lock->read_lock(this->lock); - pool = find_pool(this, name); - if (pool) + + addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING); + if (!addr) { - addr = pool->acquire_address(pool, id, requested); + addr = find_addr(this, pools, id, requested, MEM_POOL_NEW); + if (!addr) + { + addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN); + } } + this->lock->unlock(this->lock); + return addr; } METHOD(attribute_provider_t, release_address, bool, - private_stroke_attribute_t *this, char *name, host_t *address, - identification_t *id) + private_stroke_attribute_t *this, linked_list_t *pools, host_t *address, + identification_t *id) { + enumerator_t *enumerator; mem_pool_t *pool; bool found = FALSE; + char *name; + + enumerator = pools->create_enumerator(pools); this->lock->read_lock(this->lock); - pool = find_pool(this, name); - if (pool) + while (enumerator->enumerate(enumerator, &name)) { - found = pool->release_address(pool, address, id); + pool = find_pool(this, name); + if (pool) + { + found = pool->release_address(pool, address, id); + if (found) + { + break; + } + } } this->lock->unlock(this->lock); + enumerator->destroy(enumerator); + return found; } -METHOD(stroke_attribute_t, add_pool, void, - private_stroke_attribute_t *this, stroke_msg_t *msg) +/** + * Filter function to convert host to DNS configuration attributes + */ +static bool attr_filter(void *lock, host_t **in, + configuration_attribute_type_t *type, + void *dummy, chunk_t *data) { - if (msg->add_conn.other.sourceip_mask) + host_t *host = *in; + + switch (host->get_family(host)) { - mem_pool_t *pool; - host_t *base = NULL; - u_int32_t bits = 0; + case AF_INET: + *type = INTERNAL_IP4_DNS; + break; + case AF_INET6: + *type = INTERNAL_IP6_DNS; + break; + default: + return FALSE; + } + *data = host->get_address(host); + return TRUE; +} + +METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, + private_stroke_attribute_t *this, linked_list_t *pools, + identification_t *id, linked_list_t *vips) +{ + ike_sa_t *ike_sa; + peer_cfg_t *peer_cfg; + enumerator_t *enumerator; + attributes_t *attr; - /* if %config, add an empty pool, otherwise */ - if (msg->add_conn.other.sourceip) + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + this->lock->read_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) { - DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d", - msg->add_conn.name, msg->add_conn.other.sourceip, - msg->add_conn.other.sourceip_mask); - base = host_create_from_string(msg->add_conn.other.sourceip, 0); - if (!base) + if (streq(attr->name, peer_cfg->get_name(peer_cfg))) { - DBG1(DBG_CFG, "virtual IP address invalid, discarded"); - return; + enumerator->destroy(enumerator); + return enumerator_create_filter( + attr->dns->create_enumerator(attr->dns), + (void*)attr_filter, this->lock, + (void*)this->lock->unlock); } - bits = msg->add_conn.other.sourceip_mask; } - pool = mem_pool_create(msg->add_conn.name, base, bits); - DESTROY_IF(base); - - this->lock->write_lock(this->lock); - this->pools->insert_last(this->pools, pool); + enumerator->destroy(enumerator); this->lock->unlock(this->lock); } + return enumerator_create_empty(); } -METHOD(stroke_attribute_t, del_pool, void, - private_stroke_attribute_t *this, stroke_msg_t *msg) +METHOD(stroke_attribute_t, add_pool, void, + private_stroke_attribute_t *this, mem_pool_t *pool) { enumerator_t *enumerator; - mem_pool_t *pool; + mem_pool_t *current; + host_t *base; + int size; + + base = pool->get_base(pool); + size = pool->get_size(pool); this->lock->write_lock(this->lock); + enumerator = this->pools->create_enumerator(this->pools); - while (enumerator->enumerate(enumerator, &pool)) + while (enumerator->enumerate(enumerator, ¤t)) { - if (streq(msg->del_conn.name, pool->get_name(pool))) + if (base && current->get_base(current) && + base->ip_equals(base, current->get_base(current)) && + size == current->get_size(current)) { - this->pools->remove_at(this->pools, enumerator); + DBG1(DBG_CFG, "reusing virtual IP address pool %s", + current->get_name(current)); pool->destroy(pool); + pool = NULL; break; } } enumerator->destroy(enumerator); + + if (pool) + { + if (base) + { + DBG1(DBG_CFG, "adding virtual IP address pool %s", + pool->get_name(pool)); + } + this->pools->insert_last(this->pools, pool); + } + + this->lock->unlock(this->lock); +} + +METHOD(stroke_attribute_t, add_dns, void, + private_stroke_attribute_t *this, stroke_msg_t *msg) +{ + if (msg->add_conn.other.dns) + { + enumerator_t *enumerator; + attributes_t *attr = NULL; + host_t *host; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.other.dns, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + host = host_create_from_string(token, 0); + if (host) + { + if (!attr) + { + INIT(attr, + .name = strdup(msg->add_conn.name), + .dns = linked_list_create(), + ); + } + attr->dns->insert_last(attr->dns, host); + } + else + { + DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token); + } + } + enumerator->destroy(enumerator); + if (attr) + { + this->lock->write_lock(this->lock); + this->attrs->insert_last(this->attrs, attr); + this->lock->unlock(this->lock); + } + } +} + +METHOD(stroke_attribute_t, del_dns, void, + private_stroke_attribute_t *this, stroke_msg_t *msg) +{ + enumerator_t *enumerator; + attributes_t *attr; + + this->lock->write_lock(this->lock); + + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (streq(msg->del_conn.name, attr->name)) + { + this->attrs->remove_at(this->attrs, enumerator); + attributes_destroy(attr); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); } @@ -158,6 +340,11 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name, void *d3, u_int *offline) { mem_pool_t *pool = *poolp; + + if (pool->get_size(pool) == 0) + { + return FALSE; + } *name = pool->get_name(pool); *size = pool->get_size(pool); *online = pool->get_online(pool); @@ -166,7 +353,7 @@ static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name, } METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*, - private_stroke_attribute_t *this) + private_stroke_attribute_t *this) { this->lock->read_lock(this->lock); return enumerator_create_filter(this->pools->create_enumerator(this->pools), @@ -175,7 +362,7 @@ METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*, } METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*, - private_stroke_attribute_t *this, char *name) + private_stroke_attribute_t *this, char *name) { mem_pool_t *pool; this->lock->read_lock(this->lock); @@ -190,10 +377,11 @@ METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*, } METHOD(stroke_attribute_t, destroy, void, - private_stroke_attribute_t *this) + private_stroke_attribute_t *this) { this->lock->destroy(this->lock); this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy)); + this->attrs->destroy_function(this->attrs, (void*)attributes_destroy); free(this); } @@ -209,15 +397,17 @@ stroke_attribute_t *stroke_attribute_create() .provider = { .acquire_address = _acquire_address, .release_address = _release_address, - .create_attribute_enumerator = enumerator_create_empty, + .create_attribute_enumerator = _create_attribute_enumerator, }, .add_pool = _add_pool, - .del_pool = _del_pool, + .add_dns = _add_dns, + .del_dns = _del_dns, .create_pool_enumerator = _create_pool_enumerator, .create_lease_enumerator = _create_lease_enumerator, .destroy = _destroy, }, .pools = linked_list_create(), + .attrs = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); diff --git a/src/libcharon/plugins/stroke/stroke_attribute.h b/src/libcharon/plugins/stroke/stroke_attribute.h index 249a9899b..f1b9d135b 100644 --- a/src/libcharon/plugins/stroke/stroke_attribute.h +++ b/src/libcharon/plugins/stroke/stroke_attribute.h @@ -23,6 +23,7 @@ #include #include +#include typedef struct stroke_attribute_t stroke_attribute_t; @@ -37,18 +38,28 @@ struct stroke_attribute_t { attribute_provider_t provider; /** - * Add a virtual IP address pool. + * Add a memory pool to this virtual IP backend. * - * @param msg stroke message + * The pool gets owned by the provider, or destroyed if such a pool + * is already registered. + * + * @param pool virtual IP pool to add + */ + void (*add_pool)(stroke_attribute_t *this, mem_pool_t *pool); + + /** + * Add connection specific DNS servers. + * + * @param msg stroke add message */ - void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg); + void (*add_dns)(stroke_attribute_t *this, stroke_msg_t *msg); /** - * Remove a virtual IP address pool. + * Remove connection specific DNS servers. * - * @param msg stroke message + * @param msg stroke del message */ - void (*del_pool)(stroke_attribute_t *this, stroke_msg_t *msg); + void (*del_dns)(stroke_attribute_t *this, stroke_msg_t *msg); /** * Create an enumerator over installed pools. diff --git a/src/libcharon/plugins/stroke/stroke_ca.c b/src/libcharon/plugins/stroke/stroke_ca.c index bec35a661..763b4cc0f 100644 --- a/src/libcharon/plugins/stroke/stroke_ca.c +++ b/src/libcharon/plugins/stroke/stroke_ca.c @@ -348,16 +348,18 @@ METHOD(stroke_ca_t, check_for_hash_and_url, void, enumerator = this->sections->create_enumerator(this->sections); while (enumerator->enumerate(enumerator, (void**)§ion)) { - if (section->certuribase && cert->issued_by(cert, section->cert)) + if (section->certuribase && cert->issued_by(cert, section->cert, NULL)) { chunk_t hash, encoded; if (cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) { - hasher->allocate_hash(hasher, encoded, &hash); - section->hashes->insert_last(section->hashes, + if (hasher->allocate_hash(hasher, encoded, &hash)) + { + section->hashes->insert_last(section->hashes, identification_create_from_encoding(ID_KEY_ID, hash)); - chunk_free(&hash); + chunk_free(&hash); + } chunk_free(&encoded); } break; diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 483e3d253..e43672b18 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -52,6 +52,11 @@ struct private_stroke_config_t { * credentials */ stroke_cred_t *cred; + + /** + * Virtual IP pool / DNS backend + */ + stroke_attribute_t *attributes; }; METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, @@ -186,48 +191,48 @@ static ike_cfg_t *build_ike_cfg(private_stroke_config_t *this, stroke_msg_t *msg { stroke_end_t tmp_end; ike_cfg_t *ike_cfg; - char *interface; host_t *host; + u_int16_t ikeport; host = host_create_from_dns(msg->add_conn.other.address, 0, 0); if (host) { - interface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, host); - host->destroy(host); - if (interface) + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + host, NULL)) { DBG2(DBG_CFG, "left is other host, swapping ends"); tmp_end = msg->add_conn.me; msg->add_conn.me = msg->add_conn.other; msg->add_conn.other = tmp_end; - free(interface); + host->destroy(host); } else { + host->destroy(host); host = host_create_from_dns(msg->add_conn.me.address, 0, 0); if (host) { - interface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, host); - host->destroy(host); - if (!interface) + if (!hydra->kernel_interface->get_interface( + hydra->kernel_interface, host, NULL)) { DBG1(DBG_CFG, "left nor right host is our side, " "assuming left=local"); } - else - { - free(interface); - } - + host->destroy(host); } } } + ikeport = msg->add_conn.me.ikeport; + ikeport = (ikeport == IKEV2_UDP_PORT) ? + charon->socket->get_port(charon->socket, FALSE) : ikeport; ike_cfg = ike_cfg_create(msg->add_conn.other.sendcert != CERT_NEVER_SEND, - msg->add_conn.force_encap, - msg->add_conn.me.address, msg->add_conn.me.ikeport, - msg->add_conn.other.address, msg->add_conn.other.ikeport); + msg->add_conn.force_encap, + msg->add_conn.me.address, + msg->add_conn.me.allow_any, + ikeport, + msg->add_conn.other.address, + msg->add_conn.other.allow_any, + msg->add_conn.other.ikeport); add_proposals(this, msg->add_conn.algorithms.ike, ike_cfg, NULL); return ike_cfg; } @@ -256,6 +261,103 @@ static void build_crl_policy(auth_cfg_t *cfg, bool local, int policy) } } +/** + * Parse public key / signature strength constraints + */ +static void parse_pubkey_constraints(char *auth, auth_cfg_t *cfg) +{ + enumerator_t *enumerator; + bool rsa = FALSE, ecdsa = FALSE, rsa_len = FALSE, ecdsa_len = FALSE; + int strength; + char *token; + + enumerator = enumerator_create_token(auth, "-", ""); + while (enumerator->enumerate(enumerator, &token)) + { + bool found = FALSE; + int i; + struct { + char *name; + signature_scheme_t scheme; + key_type_t key; + } schemes[] = { + { "md5", SIGN_RSA_EMSA_PKCS1_MD5, KEY_RSA, }, + { "sha1", SIGN_RSA_EMSA_PKCS1_SHA1, KEY_RSA, }, + { "sha224", SIGN_RSA_EMSA_PKCS1_SHA224, KEY_RSA, }, + { "sha256", SIGN_RSA_EMSA_PKCS1_SHA256, KEY_RSA, }, + { "sha384", SIGN_RSA_EMSA_PKCS1_SHA384, KEY_RSA, }, + { "sha512", SIGN_RSA_EMSA_PKCS1_SHA512, KEY_RSA, }, + { "sha1", SIGN_ECDSA_WITH_SHA1_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_WITH_SHA256_DER, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_WITH_SHA384_DER, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_WITH_SHA512_DER, KEY_ECDSA, }, + { "sha256", SIGN_ECDSA_256, KEY_ECDSA, }, + { "sha384", SIGN_ECDSA_384, KEY_ECDSA, }, + { "sha512", SIGN_ECDSA_521, KEY_ECDSA, }, + }; + + if (rsa_len || ecdsa_len) + { /* expecting a key strength token */ + strength = atoi(token); + if (strength) + { + if (rsa_len) + { + cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength); + } + else if (ecdsa_len) + { + cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength); + } + } + rsa_len = ecdsa_len = FALSE; + if (strength) + { + continue; + } + } + if (streq(token, "rsa")) + { + rsa = rsa_len = TRUE; + continue; + } + if (streq(token, "ecdsa")) + { + ecdsa = ecdsa_len = TRUE; + continue; + } + if (streq(token, "pubkey")) + { + continue; + } + + for (i = 0; i < countof(schemes); i++) + { + if (streq(schemes[i].name, token)) + { + /* for each matching string, allow the scheme, if: + * - it is an RSA scheme, and we enforced RSA + * - it is an ECDSA scheme, and we enforced ECDSA + * - it is not a key type specific scheme + */ + if ((rsa && schemes[i].key == KEY_RSA) || + (ecdsa && schemes[i].key == KEY_ECDSA) || + (!rsa && !ecdsa)) + { + cfg->add(cfg, AUTH_RULE_SIGNATURE_SCHEME, + (uintptr_t)schemes[i].scheme); + } + found = TRUE; + } + } + if (!found) + { + DBG1(DBG_CFG, "ignoring invalid auth token: '%s'", token); + } + } + enumerator->destroy(enumerator); +} + /** * build authentication config */ @@ -264,10 +366,10 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { identification_t *identity; certificate_t *certificate; - char *auth, *id, *pubkey, *cert, *ca; + char *auth, *id, *pubkey, *cert, *ca, *groups; stroke_end_t *end, *other_end; auth_cfg_t *cfg; - char eap_buf[32]; + bool loose = FALSE; /* select strings */ if (local) @@ -310,52 +412,17 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, ca = other_end->ca2; } } + if (id && *id == '%' && !streq(id, "%any")) + { /* has only an effect on rightid/2 */ + loose = !local; + id++; + } if (!auth) { if (primary) { - if (local) - { /* "leftauth" not defined, fall back to deprecated "authby" */ - switch (msg->add_conn.auth_method) - { - default: - case AUTH_CLASS_PUBKEY: - auth = "pubkey"; - break; - case AUTH_CLASS_PSK: - auth = "psk"; - break; - case AUTH_CLASS_EAP: - auth = "eap"; - break; - case AUTH_CLASS_ANY: - auth = "any"; - break; - } - } - else - { /* "rightauth" not defined, fall back to deprecated "eap" */ - if (msg->add_conn.eap_type) - { - if (msg->add_conn.eap_vendor) - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d", - msg->add_conn.eap_type, - msg->add_conn.eap_vendor); - } - else - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d", - msg->add_conn.eap_type); - } - auth = eap_buf; - } - else - { /* not EAP => no constraints for this peer */ - auth = "any"; - } - } + auth = "pubkey"; } else { /* no second authentication round, fine. But load certificates @@ -398,7 +465,18 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } } } - cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + if (identity->get_type(identity) != ID_ANY) + { + cfg->add(cfg, AUTH_RULE_IDENTITY, identity); + if (loose) + { + cfg->add(cfg, AUTH_RULE_IDENTITY_LOOSE, TRUE); + } + } + else + { + identity->destroy(identity); + } /* add raw RSA public key */ pubkey = end->rsakey; @@ -431,12 +509,13 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /* groups */ - if (end->groups) + groups = primary ? end->groups : end->groups2; + if (groups) { enumerator_t *enumerator; char *group; - enumerator = enumerator_create_token(end->groups, ",", " "); + enumerator = enumerator_create_token(groups, ",", " "); while (enumerator->enumerate(enumerator, &group)) { cfg->add(cfg, AUTH_RULE_GROUP, @@ -460,75 +539,51 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, } /* authentication metod (class, actually) */ - if (streq(auth, "pubkey") || + if (strneq(auth, "pubkey", strlen("pubkey")) || strneq(auth, "rsa", strlen("rsa")) || strneq(auth, "ecdsa", strlen("ecdsa"))) { - u_int strength; - cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); build_crl_policy(cfg, local, msg->add_conn.crl_policy); - if (sscanf(auth, "rsa-%d", &strength) == 1) - { - cfg->add(cfg, AUTH_RULE_RSA_STRENGTH, (uintptr_t)strength); - } - if (sscanf(auth, "ecdsa-%d", &strength) == 1) - { - cfg->add(cfg, AUTH_RULE_ECDSA_STRENGTH, (uintptr_t)strength); - } + parse_pubkey_constraints(auth, cfg); } else if (streq(auth, "psk") || streq(auth, "secret")) { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); } + else if (strneq(auth, "xauth", 5)) + { + char *pos; + + pos = strchr(auth, '-'); + if (pos) + { + cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos)); + } + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); + if (msg->add_conn.xauth_identity) + { + cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY, + identification_create_from_string(msg->add_conn.xauth_identity)); + } + } else if (strneq(auth, "eap", 3)) { - enumerator_t *enumerator; - char *str; - int i = 0, type = 0, vendor; + eap_vendor_type_t *type; cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); - /* parse EAP string, format: eap[-type[-vendor]] */ - enumerator = enumerator_create_token(auth, "-", " "); - while (enumerator->enumerate(enumerator, &str)) + type = eap_vendor_type_from_string(auth); + if (type) { - switch (i) + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type->type); + if (type->vendor) { - case 1: - type = eap_type_from_string(str); - if (!type) - { - type = atoi(str); - if (!type) - { - DBG1(DBG_CFG, "unknown EAP method: %s", str); - break; - } - } - cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); - break; - case 2: - if (type) - { - vendor = atoi(str); - if (vendor) - { - cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); - } - else - { - DBG1(DBG_CFG, "unknown EAP vendor: %s", str); - } - } - break; - default: - break; + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, type->vendor); } - i++; + free(type); } - enumerator->destroy(enumerator); if (msg->add_conn.eap_identity) { @@ -570,7 +625,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, { identification_t *peer_id = NULL; peer_cfg_t *mediated_by = NULL; - host_t *vip = NULL; unique_policy_t unique; u_int32_t rekey = 0, reauth = 0, over, jitter; peer_cfg_t *peer_cfg; @@ -629,38 +683,6 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, { rekey = msg->add_conn.rekey.ike_lifetime - over; } - if (msg->add_conn.me.sourceip_mask) - { - if (msg->add_conn.me.sourceip) - { - vip = host_create_from_string(msg->add_conn.me.sourceip, 0); - } - if (!vip) - { /* if it is set to something like %poolname, request an address */ - if (msg->add_conn.me.subnets) - { /* use the same address as in subnet, if any */ - if (strchr(msg->add_conn.me.subnets, '.')) - { - vip = host_create_any(AF_INET); - } - else - { - vip = host_create_any(AF_INET6); - } - } - else - { - if (strchr(ike_cfg->get_my_addr(ike_cfg), ':')) - { - vip = host_create_any(AF_INET6); - } - else - { - vip = host_create_any(AF_INET); - } - } - } - } switch (msg->add_conn.unique) { case 1: /* yes */ @@ -670,6 +692,9 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, case 3: /* keep */ unique = UNIQUE_KEEP; break; + case 4: /* never */ + unique = UNIQUE_NEVER; + break; default: /* no */ unique = UNIQUE_NO; break; @@ -683,14 +708,131 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ peer_cfg = peer_cfg_create(msg->add_conn.name, - msg->add_conn.ikev2 ? 2 : 1, ike_cfg, + msg->add_conn.version, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, msg->add_conn.dpd.delay, - vip, msg->add_conn.other.sourceip_mask ? - msg->add_conn.name : msg->add_conn.other.sourceip, + msg->add_conn.mobike, msg->add_conn.aggressive, + msg->add_conn.dpd.delay, msg->add_conn.dpd.timeout, msg->add_conn.ikeme.mediation, mediated_by, peer_id); + if (msg->add_conn.other.sourceip) + { + enumerator_t *enumerator; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.other.sourceip, + ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (streq(token, "%modeconfig") || streq(token, "%modecfg") || + streq(token, "%config") || streq(token, "%cfg") || + streq(token, "%config4") || streq(token, "%config6")) + { + /* empty pool, uses connection name */ + this->attributes->add_pool(this->attributes, + mem_pool_create(msg->add_conn.name, NULL, 0)); + peer_cfg->add_pool(peer_cfg, msg->add_conn.name); + } + else if (*token == '%') + { + /* external named pool */ + peer_cfg->add_pool(peer_cfg, token + 1); + } + else + { + /* in-memory pool, named using CIDR notation */ + host_t *base; + int bits; + + base = host_create_from_subnet(token, &bits); + if (base) + { + this->attributes->add_pool(this->attributes, + mem_pool_create(token, base, bits)); + peer_cfg->add_pool(peer_cfg, token); + base->destroy(base); + } + else + { + DBG1(DBG_CFG, "IP pool %s invalid, ignored", token); + } + } + } + enumerator->destroy(enumerator); + } + + if (msg->add_conn.me.sourceip) + { + enumerator_t *enumerator; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.me.sourceip, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + host_t *vip = NULL; + + if (streq(token, "%modeconfig") || streq(token, "%modecfg") || + streq(token, "%config") || streq(token, "%cfg")) + { /* try to deduce an address family */ + if (msg->add_conn.me.subnets) + { /* use the same family as in local subnet, if any */ + if (strchr(msg->add_conn.me.subnets, '.')) + { + vip = host_create_any(AF_INET); + } + else + { + vip = host_create_any(AF_INET6); + } + } + else if (msg->add_conn.other.subnets) + { /* use the same family as in remote subnet, if any */ + if (strchr(msg->add_conn.other.subnets, '.')) + { + vip = host_create_any(AF_INET); + } + else + { + vip = host_create_any(AF_INET6); + } + } + else + { + if (strchr(ike_cfg->get_my_addr(ike_cfg, NULL), ':')) + { + vip = host_create_any(AF_INET6); + } + else + { + vip = host_create_any(AF_INET); + } + } + } + else if (streq(token, "%config4")) + { + vip = host_create_any(AF_INET); + } + else if (streq(token, "%config6")) + { + vip = host_create_any(AF_INET6); + } + else + { + vip = host_create_from_string(token, 0); + if (vip) + { + DBG1(DBG_CFG, "ignored invalid subnet token: %s", token); + } + } + + if (vip) + { + peer_cfg->add_virtual_ip(peer_cfg, vip); + } + } + enumerator->destroy(enumerator); + } + /* build leftauth= */ auth_cfg = build_auth_cfg(this, msg, TRUE, TRUE); if (auth_cfg) @@ -1029,8 +1171,8 @@ METHOD(stroke_config_t, set_user_credentials, void, return; } - /* replace/set the username in the first EAP auth_cfg, also look for a - * suitable remote ID. + /* replace/set the username in the first EAP/XAuth auth_cfg, also look for + * a suitable remote ID. * note that adding the identity here is not fully thread-safe as the * peer_cfg and in turn the auth_cfg could be in use. for the default use * case (setting user credentials before upping the connection) this will @@ -1049,16 +1191,25 @@ METHOD(stroke_config_t, set_user_credentials, void, } auth_class = (uintptr_t)auth_cfg->get(auth_cfg, AUTH_RULE_AUTH_CLASS); - if (auth_class == AUTH_CLASS_EAP) + if (auth_class == AUTH_CLASS_EAP || auth_class == AUTH_CLASS_XAUTH) { - auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); - /* if aaa_identity is specified use that as remote ID */ - identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY); - if (identity && identity->get_type(identity) != ID_ANY) + if (auth_class == AUTH_CLASS_EAP) { - gw = identity; + auth_cfg->add(auth_cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); + /* if aaa_identity is specified use that as remote ID */ + identity = auth_cfg->get(auth_cfg, AUTH_RULE_AAA_IDENTITY); + if (identity && identity->get_type(identity) != ID_ANY) + { + gw = identity; + } + DBG1(DBG_CFG, " configured EAP-Identity %Y", id); + } + else + { + auth_cfg->add(auth_cfg, AUTH_RULE_XAUTH_IDENTITY, + id->clone(id)); + DBG1(DBG_CFG, " configured XAuth username %Y", id); } - DBG1(DBG_CFG, " configured EAP-Identity %Y", id); type = SHARED_EAP; break; } @@ -1149,7 +1300,8 @@ METHOD(stroke_config_t, destroy, void, /* * see header file */ -stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) +stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred, + stroke_attribute_t *attributes) { private_stroke_config_t *this; @@ -1169,6 +1321,7 @@ stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred) .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), .ca = ca, .cred = cred, + .attributes = attributes, ); return &this->public; diff --git a/src/libcharon/plugins/stroke/stroke_config.h b/src/libcharon/plugins/stroke/stroke_config.h index 450d517f3..894e03ce4 100644 --- a/src/libcharon/plugins/stroke/stroke_config.h +++ b/src/libcharon/plugins/stroke/stroke_config.h @@ -26,6 +26,7 @@ #include #include "stroke_ca.h" #include "stroke_cred.h" +#include "stroke_attribute.h" typedef struct stroke_config_t stroke_config_t; @@ -71,6 +72,7 @@ struct stroke_config_t { /** * Create a stroke_config instance. */ -stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred); +stroke_config_t *stroke_config_create(stroke_ca_t *ca, stroke_cred_t *cred, + stroke_attribute_t *attributes); #endif /** STROKE_CONFIG_H_ @}*/ diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 729e9d757..233d4088f 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -58,11 +58,11 @@ struct stroke_log_info_t { * logging to the stroke interface */ static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level, - ike_sa_t *ike_sa, char *format, va_list args) + ike_sa_t *ike_sa, char *message) { if (level <= info->level) { - if (vfprintf(info->out, format, args) < 0 || + if (fprintf(info->out, "%s", message) < 0 || fprintf(info->out, "\n") < 0 || fflush(info->out) != 0) { @@ -126,14 +126,6 @@ METHOD(stroke_control_t, initiate, void, msg->initiate.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", - peer_cfg->get_ike_version(peer_cfg)); - peer_cfg->destroy(peer_cfg); - return; - } - child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); if (child_cfg == NULL) { @@ -157,14 +149,10 @@ METHOD(stroke_control_t, initiate, void, } else { - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - continue; - } child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); if (child_cfg) { @@ -419,10 +407,10 @@ METHOD(stroke_control_t, rekey, void, METHOD(stroke_control_t, terminate_srcip, void, private_stroke_control_t *this, stroke_msg_t *msg, FILE *out) { - enumerator_t *enumerator; + enumerator_t *enumerator, *vips; ike_sa_t *ike_sa; host_t *start = NULL, *end = NULL, *vip; - chunk_t chunk_start, chunk_end = chunk_empty, chunk_vip; + chunk_t chunk_start, chunk_end = chunk_empty, chunk; if (msg->terminate_srcip.start) { @@ -450,33 +438,40 @@ METHOD(stroke_control_t, terminate_srcip, void, charon->controller, TRUE); while (enumerator->enumerate(enumerator, &ike_sa)) { - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (!vip) - { - continue; - } - if (!end) + bool match = FALSE; + + vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); + while (vips->enumerate(vips, &vip)) { - if (!vip->ip_equals(vip, start)) + if (!end) { - continue; + if (vip->ip_equals(vip, start)) + { + match = TRUE; + break; + } } - } - else - { - chunk_vip = vip->get_address(vip); - if (chunk_vip.len != chunk_start.len || - chunk_vip.len != chunk_end.len || - memcmp(chunk_vip.ptr, chunk_start.ptr, chunk_vip.len) < 0 || - memcmp(chunk_vip.ptr, chunk_end.ptr, chunk_vip.len) > 0) + else { - continue; + chunk = vip->get_address(vip); + if (chunk.len == chunk_start.len && + chunk.len == chunk_end.len && + memcmp(chunk.ptr, chunk_start.ptr, chunk.len) >= 0 && + memcmp(chunk.ptr, chunk_end.ptr, chunk.len) <= 0) + { + match = TRUE; + break; + } } } + vips->destroy(vips); - /* schedule delete asynchronously */ - lib->processor->queue_job(lib->processor, (job_t*) + if (match) + { + /* schedule delete asynchronously */ + lib->processor->queue_job(lib->processor, (job_t*) delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE)); + } } enumerator->destroy(enumerator); start->destroy(start); @@ -568,14 +563,6 @@ METHOD(stroke_control_t, route, void, msg->route.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", - peer_cfg->get_ike_version(peer_cfg)); - peer_cfg->destroy(peer_cfg); - return; - } - child_cfg = get_child_from_peer(peer_cfg, msg->route.name); if (child_cfg == NULL) { @@ -599,14 +586,10 @@ METHOD(stroke_control_t, route, void, } else { - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - continue; - } child_cfg = get_child_from_peer(peer_cfg, msg->route.name); if (child_cfg) { diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index a2a6d6d9f..ebc09c0d5 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -675,7 +675,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, pin_data.keyid = chunk; pin_data.try = 1; cb = callback_cred_create_shared((void*)pin_cb, &pin_data); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); + lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); } else { @@ -684,7 +684,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, id = identification_create_from_encoding(ID_KEY_ID, chunk); mem = mem_cred_create(); mem->add_shared(mem, shared, id, NULL); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); + lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); } /* unlock: smartcard needs the pin and potentially calls public set */ @@ -722,7 +722,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, if (key) { - DBG1(DBG_CFG, " loaded private key from %.*s", sc.len, sc.ptr); + DBG1(DBG_CFG, " loaded private key from %.*s", (int)sc.len, sc.ptr); this->creds->add_key(this->creds, key); } return TRUE; @@ -792,7 +792,7 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, pp_data.path = path; pp_data.try = 1; cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); + lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, BUILD_FROM_FILE, path, BUILD_END); @@ -809,7 +809,7 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret); mem = mem_cred_create(); mem->add_shared(mem, shared, NULL); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); + lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, BUILD_FROM_FILE, path, BUILD_END); @@ -1181,7 +1181,8 @@ stroke_cred_t *stroke_cred_create() lib->credmgr->add_set(lib->credmgr, &this->creds->set); this->force_ca_cert = lib->settings->get_bool(lib->settings, - "charon.plugins.stroke.ignore_missing_ca_basic_constraint", FALSE); + "%s.plugins.stroke.ignore_missing_ca_basic_constraint", + FALSE, charon->name); load_certs(this); load_secrets(this, SECRETS_FILE, 0, NULL); diff --git a/src/libcharon/plugins/stroke/stroke_handler.c b/src/libcharon/plugins/stroke/stroke_handler.c new file mode 100644 index 000000000..523151efb --- /dev/null +++ b/src/libcharon/plugins/stroke/stroke_handler.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "stroke_handler.h" + +#include +#include +#include + +typedef struct private_stroke_handler_t private_stroke_handler_t; + +/** + * Private data of an stroke_handler_t object. + */ +struct private_stroke_handler_t { + + /** + * Public stroke_handler_t interface. + */ + stroke_handler_t public; + + /** + * List of connection specific attributes, as attributes_t + */ + linked_list_t *attrs; + + /** + * rwlock to lock access to pools + */ + rwlock_t *lock; +}; + +/** + * Attributes assigned to a connection + */ +typedef struct { + /** name of the connection */ + char *name; + /** list of DNS attributes, as host_t */ + linked_list_t *dns; +} attributes_t; + +/** + * Destroy an attributes_t entry + */ +static void attributes_destroy(attributes_t *this) +{ + this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); + free(this->name); + free(this); +} + +/** + * Filter function to convert host to DNS configuration attributes + */ +static bool attr_filter(void *lock, host_t **in, + configuration_attribute_type_t *type, + void *dummy, chunk_t *data) +{ + host_t *host = *in; + + switch (host->get_family(host)) + { + case AF_INET: + *type = INTERNAL_IP4_DNS; + break; + case AF_INET6: + *type = INTERNAL_IP6_DNS; + break; + default: + return FALSE; + } + if (host->is_anyaddr(host)) + { + *data = chunk_empty; + } + else + { + *data = host->get_address(host); + } + return TRUE; +} + +METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, + private_stroke_handler_t *this, identification_t *server, + linked_list_t *vips) +{ + ike_sa_t *ike_sa; + peer_cfg_t *peer_cfg; + enumerator_t *enumerator; + attributes_t *attr; + + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + this->lock->read_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (streq(attr->name, peer_cfg->get_name(peer_cfg))) + { + enumerator->destroy(enumerator); + return enumerator_create_filter( + attr->dns->create_enumerator(attr->dns), + (void*)attr_filter, this->lock, + (void*)this->lock->unlock); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + } + return enumerator_create_empty(); +} + +METHOD(stroke_handler_t, add_attributes, void, + private_stroke_handler_t *this, stroke_msg_t *msg) +{ + if (msg->add_conn.me.dns) + { + enumerator_t *enumerator; + attributes_t *attr = NULL; + host_t *host; + char *token; + + enumerator = enumerator_create_token(msg->add_conn.me.dns, ",", " "); + while (enumerator->enumerate(enumerator, &token)) + { + if (streq(token, "%config") || streq(token, "%config4")) + { + host = host_create_any(AF_INET); + } + else if (streq(token, "%config6")) + { + host = host_create_any(AF_INET6); + } + else + { + host = host_create_from_string(token, 0); + } + if (host) + { + if (!attr) + { + INIT(attr, + .name = strdup(msg->add_conn.name), + .dns = linked_list_create(), + ); + } + attr->dns->insert_last(attr->dns, host); + } + else + { + DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token); + } + } + enumerator->destroy(enumerator); + if (attr) + { + this->lock->write_lock(this->lock); + this->attrs->insert_last(this->attrs, attr); + this->lock->unlock(this->lock); + } + } +} + +METHOD(stroke_handler_t, del_attributes, void, + private_stroke_handler_t *this, stroke_msg_t *msg) +{ + enumerator_t *enumerator; + attributes_t *attr; + + this->lock->write_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (streq(msg->del_conn.name, attr->name)) + { + this->attrs->remove_at(this->attrs, enumerator); + attributes_destroy(attr); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +METHOD(stroke_handler_t, destroy, void, + private_stroke_handler_t *this) +{ + this->lock->destroy(this->lock); + this->attrs->destroy_function(this->attrs, (void*)attributes_destroy); + free(this); +} + +/** + * See header + */ +stroke_handler_t *stroke_handler_create() +{ + private_stroke_handler_t *this; + + INIT(this, + .public = { + .handler = { + .handle = (void*)return_false, + .release = (void*)return_false, + .create_attribute_enumerator = _create_attribute_enumerator, + }, + .add_attributes = _add_attributes, + .del_attributes = _del_attributes, + .destroy = _destroy, + }, + .attrs = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/stroke/stroke_handler.h b/src/libcharon/plugins/stroke/stroke_handler.h new file mode 100644 index 000000000..ab76f80b0 --- /dev/null +++ b/src/libcharon/plugins/stroke/stroke_handler.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup stroke_handler stroke_handler + * @{ @ingroup stroke + */ + +#ifndef STROKE_HANDLER_H_ +#define STROKE_HANDLER_H_ + +#include +#include + +typedef struct stroke_handler_t stroke_handler_t; + +/** + * Handler requesting DNS attributes as defined with leftdns option. + */ +struct stroke_handler_t { + + /** + * Implements the attribute_handler_t interface + */ + attribute_handler_t handler; + + /** + * Add connection specific configuration attributes. + * + * @param msg stroke message + */ + void (*add_attributes)(stroke_handler_t *this, stroke_msg_t *msg); + + /** + * Remove connection specific configuration attributes. + * + * @param msg stroke message + */ + void (*del_attributes)(stroke_handler_t *this, stroke_msg_t *msg); + + /** + * Destroy a stroke_handler_t. + */ + void (*destroy)(stroke_handler_t *this); +}; + +/** + * Create a stroke_handler instance. + */ +stroke_handler_t *stroke_handler_create(); + +#endif /** STROKE_HANDLER_H_ @}*/ diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 514a91e2b..c012ff25d 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -17,6 +17,7 @@ #include #include +#include #ifdef HAVE_MALLINFO #include @@ -50,6 +51,11 @@ struct private_stroke_list_t { */ stroke_list_t public; + /** + * Kind of *swan we run + */ + char *swan; + /** * timestamp of daemon start */ @@ -115,11 +121,23 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) if (all) { proposal_t *ike_proposal; + identification_t *eap_id; + + eap_id = ike_sa->get_other_eap_id(ike_sa); + + if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa))) + { + fprintf(out, "%12s[%d]: Remote %s identity: %Y\n", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_sa->get_version(ike_sa) == IKEV1 ? "XAuth" : "EAP", + eap_id); + } ike_proposal = ike_sa->get_proposal(ike_sa); - fprintf(out, "%12s[%d]: IKE SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s", + fprintf(out, "%12s[%d]: %N SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_version_names, ike_sa->get_version(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); @@ -191,6 +209,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) proposal_t *proposal; child_cfg_t *config = child_sa->get_config(child_sa); + now = time_monotonic(NULL); fprintf(out, "%12s{%d}: %N, %N%s", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), @@ -254,7 +273,6 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) } } - now = time_monotonic(NULL); child_sa->get_usestats(child_sa, TRUE, &use_in, &bytes_in); fprintf(out, ", %" PRIu64 " bytes_i", bytes_in); if (use_in) @@ -289,6 +307,11 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) } } + else if (child_sa->get_state(child_sa) == CHILD_REKEYING) + { + rekey = child_sa->get_lifetime(child_sa, TRUE); + fprintf(out, ", expires in %V", &now, &rekey); + } fprintf(out, "\n%12s{%d}: %#R=== %#R\n", child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), @@ -315,15 +338,16 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); while (enumerator->enumerate(enumerator, &auth)) { - fprintf(out, "%12s: %s [%Y] uses ", name, local ? "local: " : "remote:", - auth->get(auth, AUTH_RULE_IDENTITY)); - - auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); - if (auth_class != AUTH_CLASS_EAP) + fprintf(out, "%12s: %s", name, local ? "local: " : "remote:"); + id = auth->get(auth, AUTH_RULE_IDENTITY); + if (id) { - fprintf(out, "%N authentication\n", auth_class_names, auth_class); + fprintf(out, " [%Y]", id); } - else + fprintf(out, " uses "); + + auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + if (auth_class == AUTH_CLASS_EAP) { if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK) { @@ -350,6 +374,21 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) } fprintf(out, "\n"); } + else if (auth_class == AUTH_CLASS_XAUTH) + { + fprintf(out, "%N authentication: %s", auth_class_names, auth_class, + auth->get(auth, AUTH_RULE_XAUTH_BACKEND) ?: "any"); + id = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY); + if (id) + { + fprintf(out, " with XAuth identity '%Y'", id); + } + fprintf(out, "\n"); + } + else + { + fprintf(out, "%N authentication\n", auth_class_names, auth_class); + } cert = auth->get(auth, AUTH_RULE_CA_CERT); if (cert) @@ -414,16 +453,25 @@ METHOD(stroke_list_t, status, void, if (all) { peer_cfg_t *peer_cfg; + ike_version_t ike_version; char *pool; host_t *host; u_int32_t dpd; time_t since, now; u_int size, online, offline, i; + struct utsname utsname; + now = time_monotonic(NULL); since = time(NULL) - (now - this->uptime); - fprintf(out, "Status of IKEv2 charon daemon (strongSwan "VERSION"):\n"); - fprintf(out, " uptime: %V, since %T\n", &now, &this->uptime, &since, FALSE); + fprintf(out, "Status of IKE charon daemon (%sSwan "VERSION, this->swan); + if (uname(&utsname) == 0) + { + fprintf(out, ", %s %s, %s", + utsname.sysname, utsname.release, utsname.machine); + } + fprintf(out, "):\n uptime: %V, since %T\n", &now, &this->uptime, &since, + FALSE); #ifdef HAVE_MALLINFO { struct mallinfo mi = mallinfo(); @@ -469,7 +517,7 @@ METHOD(stroke_list_t, status, void, enumerator->destroy(enumerator); enumerator = hydra->kernel_interface->create_address_enumerator( - hydra->kernel_interface, FALSE, FALSE); + hydra->kernel_interface, ADDR_TYPE_REGULAR); fprintf(out, "Listening IP addresses:\n"); while (enumerator->enumerate(enumerator, (void**)&host)) { @@ -479,18 +527,30 @@ METHOD(stroke_list_t, status, void, fprintf(out, "Connections:\n"); enumerator = charon->backends->create_peer_cfg_enumerator( - charon->backends, NULL, NULL, NULL, NULL); + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2 || - (name && !streq(name, peer_cfg->get_name(peer_cfg)))) + char *my_addr, *other_addr; + bool my_allow_any, other_allow_any; + + if (name && !streq(name, peer_cfg->get_name(peer_cfg))) { continue; } ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg), - ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg)); + ike_version = peer_cfg->get_ike_version(peer_cfg); + my_addr = ike_cfg->get_my_addr(ike_cfg, &my_allow_any); + other_addr = ike_cfg->get_other_addr(ike_cfg, &other_allow_any); + fprintf(out, "%12s: %s%s...%s%s %N", peer_cfg->get_name(peer_cfg), + my_allow_any ? "%":"", my_addr, + other_allow_any ? "%":"", other_addr, + ike_version_names, ike_version); + + if (ike_version == IKEV1 && peer_cfg->use_aggressive(peer_cfg)) + { + fprintf(out, " Aggressive"); + } dpd = peer_cfg->get_dpd(peer_cfg); if (dpd) @@ -666,15 +726,12 @@ static void list_public_key(public_key_t *public, FILE *out) private_key_t *private = NULL; chunk_t keyid; identification_t *id; - auth_cfg_t *auth; if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid)) { id = identification_create_from_encoding(ID_KEY_ID, keyid); - auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, - public->get_type(public), id, auth); - auth->destroy(auth); + public->get_type(public), id, NULL); id->destroy(id); } @@ -819,8 +876,8 @@ static void stroke_list_certs(linked_list_t *list, char *label, x509_flag_t flag_mask; /* mask all auxiliary flags */ - flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH | - X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS ); + flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH | X509_IKE_INTERMEDIATE | + X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS); enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, (void**)&cert)) @@ -1059,7 +1116,7 @@ static void stroke_list_crls(linked_list_t *list, bool utc, FILE *out) } if (crl->is_delta_crl(crl, &chunk)) { - chunk = chunk_skip_zero(chunk); + chunk = chunk_skip_zero(chunk); fprintf(out, " delta for: %#B\n", &chunk); } @@ -1151,7 +1208,15 @@ static void print_alg(FILE *out, int *len, enum_name_t *alg_names, int alg_type, char alg_name[BUF_LEN]; int alg_name_len; - alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type, plugin_name); + if (alg_names) + { + alg_name_len = sprintf(alg_name, " %N[%s]", alg_names, alg_type, + plugin_name); + } + else + { + alg_name_len = sprintf(alg_name, " [%s]", plugin_name); + } if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) { fprintf(out, "\n "); @@ -1234,6 +1299,14 @@ static void list_algs(FILE *out) print_alg(out, &len, rng_quality_names, quality, plugin_name); } enumerator->destroy(enumerator); + fprintf(out, "\n nonce-gen: "); + len = 13; + enumerator = lib->crypto->create_nonce_gen_enumerator(lib->crypto); + while (enumerator->enumerate(enumerator, &plugin_name)) + { + print_alg(out, &len, NULL, 0, plugin_name); + } + enumerator->destroy(enumerator); fprintf(out, "\n"); } @@ -1277,7 +1350,7 @@ static void list_plugins(FILE *out) fprintf(out, " %s\n", str); break; case FEATURE_SDEPEND: - fprintf(out, " %s(soft)\n", str); + fprintf(out, " %s (soft)\n", str); break; default: break; @@ -1450,16 +1523,22 @@ stroke_list_t *stroke_list_create(stroke_attribute_t *attribute) INIT(this, .public = { - .list = _list, .status = _status, .leases = _leases, .destroy = _destroy, }, .uptime = time_monotonic(NULL), + .swan = "strong", .attribute = attribute, ); + if (lib->settings->get_bool(lib->settings, + "charon.i_dont_care_about_security_and_use_aggressive_mode_psk", FALSE)) + { + this->swan = "weak"; + } + return &this->public; } diff --git a/src/libcharon/plugins/stroke/stroke_plugin.c b/src/libcharon/plugins/stroke/stroke_plugin.c index 2884db4bf..4e47a120d 100644 --- a/src/libcharon/plugins/stroke/stroke_plugin.c +++ b/src/libcharon/plugins/stroke/stroke_plugin.c @@ -42,10 +42,45 @@ METHOD(plugin_t, get_name, char*, return "stroke"; } +/** + * Register stroke plugin features + */ +static bool register_stroke(private_stroke_plugin_t *this, + plugin_feature_t *feature, bool reg, void *data) +{ + if (reg) + { + this->socket = stroke_socket_create(); + } + else + { + DESTROY_IF(this->socket); + } + return TRUE; +} + +METHOD(plugin_t, get_features, int, + private_stroke_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK((plugin_feature_callback_t)register_stroke, NULL), + PLUGIN_PROVIDE(CUSTOM, "stroke"), + PLUGIN_SDEPEND(PRIVKEY, KEY_RSA), + PLUGIN_SDEPEND(PRIVKEY, KEY_ECDSA), + PLUGIN_SDEPEND(PRIVKEY, KEY_DSA), + PLUGIN_SDEPEND(CERT_DECODE, CERT_ANY), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509_CRL), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509_AC), + PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY), + }; + *features = f; + return countof(f); +} + METHOD(plugin_t, destroy, void, private_stroke_plugin_t *this) { - this->socket->destroy(this->socket); free(this); } @@ -61,17 +96,12 @@ plugin_t *stroke_plugin_create() .plugin = { .get_name = _get_name, .reload = (void*)return_false, + .get_features = _get_features, .destroy = _destroy, }, }, - .socket = stroke_socket_create(), ); - if (this->socket == NULL) - { - free(this); - return NULL; - } return &this->public.plugin; } diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 57648feb8..241f0fbf6 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -37,6 +37,7 @@ #include "stroke_cred.h" #include "stroke_ca.h" #include "stroke_attribute.h" +#include "stroke_handler.h" #include "stroke_list.h" /** @@ -63,16 +64,6 @@ struct private_stroke_socket_t { */ int socket; - /** - * job accepting stroke messages - */ - callback_job_t *receiver; - - /** - * job handling stroke messages - */ - callback_job_t *handler; - /** * queued stroke commands */ @@ -108,6 +99,11 @@ struct private_stroke_socket_t { */ stroke_attribute_t *attribute; + /** + * attribute handler (requests only) + */ + stroke_handler_t *handler; + /** * controller to control daemon */ @@ -181,6 +177,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) pop_string(msg, &end->address); pop_string(msg, &end->subnets); pop_string(msg, &end->sourceip); + pop_string(msg, &end->dns); pop_string(msg, &end->auth); pop_string(msg, &end->auth2); pop_string(msg, &end->id); @@ -191,12 +188,14 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) pop_string(msg, &end->ca); pop_string(msg, &end->ca2); pop_string(msg, &end->groups); + pop_string(msg, &end->groups2); pop_string(msg, &end->cert_policy); pop_string(msg, &end->updown); DBG2(DBG_CFG, " %s=%s", label, end->address); DBG2(DBG_CFG, " %ssubnet=%s", label, end->subnets); DBG2(DBG_CFG, " %ssourceip=%s", label, end->sourceip); + DBG2(DBG_CFG, " %sdns=%s", label, end->dns); DBG2(DBG_CFG, " %sauth=%s", label, end->auth); DBG2(DBG_CFG, " %sauth2=%s", label, end->auth2); DBG2(DBG_CFG, " %sid=%s", label, end->id); @@ -207,6 +206,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end) DBG2(DBG_CFG, " %sca=%s", label, end->ca); DBG2(DBG_CFG, " %sca2=%s", label, end->ca2); DBG2(DBG_CFG, " %sgroups=%s", label, end->groups); + DBG2(DBG_CFG, " %sgroups2=%s", label, end->groups2); DBG2(DBG_CFG, " %supdown=%s", label, end->updown); } @@ -223,23 +223,28 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) pop_end(msg, "right", &msg->add_conn.other); pop_string(msg, &msg->add_conn.eap_identity); pop_string(msg, &msg->add_conn.aaa_identity); + pop_string(msg, &msg->add_conn.xauth_identity); pop_string(msg, &msg->add_conn.algorithms.ike); pop_string(msg, &msg->add_conn.algorithms.esp); pop_string(msg, &msg->add_conn.ikeme.mediated_by); pop_string(msg, &msg->add_conn.ikeme.peerid); DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity); DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity); + DBG2(DBG_CFG, " xauth_identity=%s", msg->add_conn.xauth_identity); DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay); + DBG2(DBG_CFG, " dpdtimeout=%d", msg->add_conn.dpd.timeout); DBG2(DBG_CFG, " dpdaction=%d", msg->add_conn.dpd.action); DBG2(DBG_CFG, " closeaction=%d", msg->add_conn.close_action); DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by); DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid); + DBG2(DBG_CFG, " keyexchange=ikev%u", msg->add_conn.version); this->config->add(this->config, msg); - this->attribute->add_pool(this->attribute, msg); + this->attribute->add_dns(this->attribute, msg); + this->handler->add_attributes(this->handler, msg); } /** @@ -251,7 +256,8 @@ static void stroke_del_conn(private_stroke_socket_t *this, stroke_msg_t *msg) DBG1(DBG_CFG, "received stroke: delete connection '%s'", msg->del_conn.name); this->config->del(this->config, msg); - this->attribute->del_pool(this->attribute, msg); + this->attribute->del_dns(this->attribute, msg); + this->handler->del_attributes(this->handler, msg); } /** @@ -514,12 +520,14 @@ static void stroke_loglevel(private_stroke_socket_t *this, while (enumerator->enumerate(enumerator, &sys_logger)) { sys_logger->set_level(sys_logger, group, msg->loglevel.level); + charon->bus->add_logger(charon->bus, &sys_logger->logger); } enumerator->destroy(enumerator); enumerator = charon->file_loggers->create_enumerator(charon->file_loggers); while (enumerator->enumerate(enumerator, &file_logger)) { file_logger->set_level(file_logger, group, msg->loglevel.level); + charon->bus->add_logger(charon->bus, &file_logger->logger); } enumerator->destroy(enumerator); } @@ -696,7 +704,7 @@ static job_requeue_t handle(private_stroke_socket_t *this) this->handling++; thread_cleanup_pop(TRUE); job = callback_job_create_with_prio((callback_job_cb_t)process, ctx, - (void*)stroke_job_context_destroy, this->handler, JOB_PRIO_HIGH); + (void*)stroke_job_context_destroy, NULL, JOB_PRIO_HIGH); lib->processor->queue_job(lib->processor, (job_t*)job); return JOB_REQUEUE_DIRECT; } @@ -762,7 +770,8 @@ static bool open_socket(private_stroke_socket_t *this) return FALSE; } umask(old); - if (chown(socket_addr.sun_path, charon->uid, charon->gid) != 0) + if (chown(socket_addr.sun_path, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing stroke socket permissions failed: %s", strerror(errno)); @@ -781,8 +790,6 @@ static bool open_socket(private_stroke_socket_t *this) METHOD(stroke_socket_t, destroy, void, private_stroke_socket_t *this) { - this->handler->cancel(this->handler); - this->receiver->cancel(this->receiver); this->commands->destroy_function(this->commands, (void*)stroke_job_context_destroy); this->condvar->destroy(this->condvar); this->mutex->destroy(this->mutex); @@ -790,10 +797,12 @@ METHOD(stroke_socket_t, destroy, void, lib->credmgr->remove_set(lib->credmgr, &this->cred->set); charon->backends->remove_backend(charon->backends, &this->config->backend); hydra->attributes->remove_provider(hydra->attributes, &this->attribute->provider); + hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler); this->cred->destroy(this->cred); this->ca->destroy(this->ca); this->config->destroy(this->config); this->attribute->destroy(this->attribute); + this->handler->destroy(this->handler); this->control->destroy(this->control); this->list->destroy(this->list); free(this); @@ -820,8 +829,9 @@ stroke_socket_t *stroke_socket_create() this->cred = stroke_cred_create(); this->attribute = stroke_attribute_create(); + this->handler = stroke_handler_create(); this->ca = stroke_ca_create(this->cred); - this->config = stroke_config_create(this->ca, this->cred); + this->config = stroke_config_create(this->ca, this->cred, this->attribute); this->control = stroke_control_create(); this->list = stroke_list_create(this->attribute); @@ -829,20 +839,22 @@ stroke_socket_t *stroke_socket_create() this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT); this->commands = linked_list_create(); this->max_concurrent = lib->settings->get_int(lib->settings, - "charon.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT); + "%s.plugins.stroke.max_concurrent", MAX_CONCURRENT_DEFAULT, + charon->name); lib->credmgr->add_set(lib->credmgr, &this->ca->set); lib->credmgr->add_set(lib->credmgr, &this->cred->set); charon->backends->add_backend(charon->backends, &this->config->backend); hydra->attributes->add_provider(hydra->attributes, &this->attribute->provider); + hydra->attributes->add_handler(hydra->attributes, &this->handler->handler); - this->receiver = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->receiver); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); - this->handler = callback_job_create_with_prio((callback_job_cb_t)handle, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->handler); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)handle, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/tnc_ifmap/Makefile.in b/src/libcharon/plugins/tnc_ifmap/Makefile.in index 54deb7cd7..5ead4379a 100644 --- a/src/libcharon/plugins/tnc_ifmap/Makefile.in +++ b/src/libcharon/plugins/tnc_ifmap/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_tnc_ifmap_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_tnc_ifmap_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnc_ifmap_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_listener.c b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_listener.c index 4fd33696c..eac285ca3 100644 --- a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_listener.c +++ b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_listener.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -49,7 +49,7 @@ static bool publish_device_ip_addresses(private_tnc_ifmap_listener_t *this) bool success = TRUE; enumerator = hydra->kernel_interface->create_address_enumerator( - hydra->kernel_interface, FALSE, FALSE); + hydra->kernel_interface, ADDR_TYPE_REGULAR); while (enumerator->enumerate(enumerator, &host)) { if (!this->ifmap->publish_device_ip(this->ifmap, host)) @@ -87,7 +87,7 @@ static bool reload_metadata(private_tnc_ifmap_listener_t *this) } } enumerator->destroy(enumerator); - + return success; } diff --git a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap.c b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap.c index 913cdab12..b13193612 100644 --- a/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap.c +++ b/src/libcharon/plugins/tnc_ifmap/tnc_ifmap_soap.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,6 +16,7 @@ #include "tnc_ifmap_soap.h" #include +#include #include #include @@ -27,7 +28,7 @@ #define IFMAP_META_NS "http://www.trustedcomputinggroup.org/2010/IFMAP-METADATA/2" #define IFMAP_LOGFILE "strongswan_ifmap.log" #define IFMAP_SERVER "https://localhost:8443/" - + typedef struct private_tnc_ifmap_soap_t private_tnc_ifmap_soap_t; /** @@ -41,7 +42,7 @@ struct private_tnc_ifmap_soap_t { tnc_ifmap_soap_t public; /** - * Axis2/C environment + * Axis2/C environment */ axutil_env_t *env; @@ -155,8 +156,8 @@ METHOD(tnc_ifmap_soap_t, newSession, bool, /* set PEP and PDP device name (defaults to IF-MAP Publisher ID) */ this->device_name = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.device_name", - this->ifmap_publisher_id); + "%s.plugins.tnc-ifmap.device_name", + this->ifmap_publisher_id, charon->name); this->device_name = strdup(this->device_name); /* free result */ @@ -174,13 +175,13 @@ METHOD(tnc_ifmap_soap_t, purgePublisher, bool, axiom_attribute_t *attr; /* build purgePublisher request */ - ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap"); + ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap"); el = axiom_element_create(this->env, NULL, "purgePublisher", ns, &request); attr = axiom_attribute_create(this->env, "session-id", - this->session_id, NULL); + this->session_id, NULL); axiom_element_add_attribute(el, this->env, attr, request); attr = axiom_attribute_create(this->env, "ifmap-publisher-id", - this->ifmap_publisher_id, NULL); + this->ifmap_publisher_id, NULL); axiom_element_add_attribute(el, this->env, attr, request); /* send purgePublisher request and receive purgePublisherReceived */ @@ -202,7 +203,7 @@ static axiom_node_t* create_access_request(private_tnc_ifmap_soap_t *this, el = axiom_element_create(this->env, NULL, "access-request", NULL, &node); snprintf(buf, BUF_LEN, "%s:%d", this->device_name, id); - attr = axiom_attribute_create(this->env, "name", buf, NULL); + attr = axiom_attribute_create(this->env, "name", buf, NULL); axiom_element_add_attribute(el, this->env, attr, node); return node; @@ -222,7 +223,7 @@ static axiom_node_t* create_identity(private_tnc_ifmap_soap_t *this, el = axiom_element_create(this->env, NULL, "identity", NULL, &node); snprintf(buf, BUF_LEN, "%Y", id); - attr = axiom_attribute_create(this->env, "name", buf, NULL); + attr = axiom_attribute_create(this->env, "name", buf, NULL); axiom_element_add_attribute(el, this->env, attr, node); switch (id->get_type(id)) @@ -260,7 +261,7 @@ static axiom_node_t* create_identity(private_tnc_ifmap_soap_t *this, "36906:other", NULL); axiom_element_add_attribute(el, this->env, attr, node); } - attr = axiom_attribute_create(this->env, "type", id_type, NULL); + attr = axiom_attribute_create(this->env, "type", id_type, NULL); axiom_element_add_attribute(el, this->env, attr, node); return node; @@ -295,7 +296,7 @@ static axiom_node_t* create_ip_address(private_tnc_ifmap_soap_t *this, { written = snprintf(pos, len, "%s%x", first ? "" : ":", 256*address.ptr[i] + address.ptr[i+1]); - if (written < 0 || written > len) + if (written < 0 || written >= len) { break; } @@ -308,11 +309,11 @@ static axiom_node_t* create_ip_address(private_tnc_ifmap_soap_t *this, { snprintf(buf, BUF_LEN, "%H", host); } - attr = axiom_attribute_create(this->env, "value", buf, NULL); + attr = axiom_attribute_create(this->env, "value", buf, NULL); axiom_element_add_attribute(el, this->env, attr, node); attr = axiom_attribute_create(this->env, "type", - host->get_family(host) == AF_INET ? "IPv4" : "IPv6", NULL); + host->get_family(host) == AF_INET ? "IPv4" : "IPv6", NULL); axiom_element_add_attribute(el, this->env, attr, node); return node; @@ -352,7 +353,7 @@ static axiom_node_t* create_metadata(private_tnc_ifmap_soap_t *this, el = axiom_element_create(this->env, NULL, metadata, ns_meta, &node2); axiom_node_add_child(node, this->env, node2); attr = axiom_attribute_create(this->env, "ifmap-cardinality", "singleValue", - NULL); + NULL); axiom_element_add_attribute(el, this->env, attr, node2); return node; @@ -374,7 +375,7 @@ static axiom_node_t* create_capability(private_tnc_ifmap_soap_t *this, ns_meta = axiom_namespace_create(this->env, IFMAP_META_NS, "meta"); el = axiom_element_create(this->env, NULL, "capability", ns_meta, &node); attr = axiom_attribute_create(this->env, "ifmap-cardinality", "multiValue", - NULL); + NULL); axiom_element_add_attribute(el, this->env, attr, node); el = axiom_element_create(this->env, NULL, "name", NULL, &node2); @@ -385,7 +386,7 @@ static axiom_node_t* create_capability(private_tnc_ifmap_soap_t *this, el = axiom_element_create(this->env, NULL, "administrative-domain", NULL, &node2); axiom_node_add_child(node, this->env, node2); text = axiom_text_create(this->env, node2, "strongswan", &node3); - + return node; } @@ -439,7 +440,7 @@ static axiom_node_t* create_delete_filter(private_tnc_ifmap_soap_t *this, snprintf(buf, BUF_LEN, "meta:%s[@ifmap-publisher-id='%s']", metadata, this->ifmap_publisher_id); - attr = axiom_attribute_create(this->env, "filter", buf, NULL); + attr = axiom_attribute_create(this->env, "filter", buf, NULL); axiom_element_add_attribute(el, this->env, attr, node); return node; @@ -506,11 +507,11 @@ METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool, axiom_node_add_child(node, this->env, create_device(this)); } - + /** * update or delete authenticated-as metadata */ - if (up) + if (up) { el = axiom_element_create(this->env, NULL, "update", NULL, &node); } @@ -534,7 +535,7 @@ METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool, /** * update or delete access-request-ip metadata */ - if (up) + if (up) { el = axiom_element_create(this->env, NULL, "update", NULL, &node); } @@ -558,7 +559,7 @@ METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool, /** * update or delete authenticated-by metadata */ - if (up) + if (up) { el = axiom_element_create(this->env, NULL, "update", NULL, &node); } @@ -605,7 +606,7 @@ METHOD(tnc_ifmap_soap_t, publish_ike_sa, bool, node = create_delete_filter(this, "capability"); } axiom_node_add_child(request, this->env, node); - + /* add access-request */ axiom_node_add_child(node, this->env, create_access_request(this, ike_sa_id)); @@ -688,9 +689,9 @@ METHOD(tnc_ifmap_soap_t, endSession, bool, axiom_attribute_t *attr; /* build endSession request */ - ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap"); + ns = axiom_namespace_create(this->env, IFMAP_NS, "ifmap"); el = axiom_element_create(this->env, NULL, "endSession", ns, &request); - attr = axiom_attribute_create(this->env, "session-id", this->session_id, NULL); + attr = axiom_attribute_create(this->env, "session-id", this->session_id, NULL); axiom_element_add_attribute(el, this->env, attr, request); /* send endSession request and receive end SessionResult */ @@ -705,7 +706,7 @@ METHOD(tnc_ifmap_soap_t, destroy, void, endSession(this); free(this->session_id); free(this->ifmap_publisher_id); - free(this->device_name); + free(this->device_name); } if (this->svc_client) { @@ -731,20 +732,20 @@ static bool axis2c_init(private_tnc_ifmap_soap_t *this) /* Getting configuration parameters from strongswan.conf */ client_home = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.client_home", - AXIS2_GETENV("AXIS2C_HOME")); + "%s.plugins.tnc-ifmap.client_home", + AXIS2_GETENV("AXIS2C_HOME"), charon->name); server = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.server", IFMAP_SERVER); + "%s.plugins.tnc-ifmap.server", IFMAP_SERVER, charon->name); server_cert = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.server_cert", NULL); + "%s.plugins.tnc-ifmap.server_cert", NULL, charon->name); key_file = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.key_file", NULL); + "%s.plugins.tnc-ifmap.key_file", NULL, charon->name); ssl_passphrase = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.ssl_passphrase", NULL); + "%s.plugins.tnc-ifmap.ssl_passphrase", NULL, charon->name); username = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.username", NULL); + "%s.plugins.tnc-ifmap.username", NULL, charon->name); password = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-ifmap.password", NULL); + "%s.plugins.tnc-ifmap.password", NULL, charon->name); if (!server_cert) { @@ -785,9 +786,9 @@ static bool axis2c_init(private_tnc_ifmap_soap_t *this) ssl_passphrase); axis2_options_set_property(options, this->env, AXIS2_SSL_PASSPHRASE, property); - } + } } - else + else { /* Set up HTTP Basic MAP client authentication */ axis2_options_set_http_auth_info(options, this->env, @@ -800,14 +801,14 @@ static bool axis2c_init(private_tnc_ifmap_soap_t *this) /* Set up https transport */ transport_in = axis2_transport_in_desc_create(this->env, - AXIS2_TRANSPORT_ENUM_HTTPS); + AXIS2_TRANSPORT_ENUM_HTTPS); transport_out = axis2_transport_out_desc_create(this->env, AXIS2_TRANSPORT_ENUM_HTTPS); transport_sender = axis2_http_transport_sender_create(this->env); axis2_transport_out_desc_set_sender(transport_out, this->env, transport_sender); axis2_options_set_transport_in(options, this->env, transport_in); - axis2_options_set_transport_out(options, this->env, transport_out); + axis2_options_set_transport_out(options, this->env, transport_out); /* Create the axis2 service client */ this->svc_client = axis2_svc_client_create(this->env, client_home); diff --git a/src/libcharon/plugins/tnc_imc/Makefile.am b/src/libcharon/plugins/tnc_imc/Makefile.am index fc1979525..5e2c30df9 100644 --- a/src/libcharon/plugins/tnc_imc/Makefile.am +++ b/src/libcharon/plugins/tnc_imc/Makefile.am @@ -1,6 +1,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs diff --git a/src/libcharon/plugins/tnc_imc/Makefile.in b/src/libcharon/plugins/tnc_imc/Makefile.in index 550c0516c..00c0d0d61 100644 --- a/src/libcharon/plugins/tnc_imc/Makefile.in +++ b/src/libcharon/plugins/tnc_imc/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_tnc_imc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_tnc_imc_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnc_imc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -287,6 +293,8 @@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c index e101cf974..65ec81dae 100644 --- a/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c +++ b/src/libcharon/plugins/tnc_imc/tnc_imc_manager.c @@ -21,6 +21,7 @@ #include #include +#include typedef struct private_tnc_imc_manager_t private_tnc_imc_manager_t; @@ -171,7 +172,7 @@ METHOD(imc_manager_t, get_preferred_language, char*, private_tnc_imc_manager_t *this) { return lib->settings->get_str(lib->settings, - "charon.plugins.tnc-imc.preferred_language", "en"); + "%s.plugins.tnc-imc.preferred_language", "en", charon->name); } METHOD(imc_manager_t, notify_connection_change, void, diff --git a/src/libcharon/plugins/tnc_imc/tnc_imc_plugin.c b/src/libcharon/plugins/tnc_imc/tnc_imc_plugin.c index a25b1843c..859dded79 100644 --- a/src/libcharon/plugins/tnc_imc/tnc_imc_plugin.c +++ b/src/libcharon/plugins/tnc_imc/tnc_imc_plugin.c @@ -44,6 +44,8 @@ METHOD(plugin_t, get_features, int, PLUGIN_CALLBACK(tnc_manager_register, tnc_imc_manager_create), PLUGIN_PROVIDE(CUSTOM, "imc-manager"), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), + PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY), }; *features = f; return countof(f); diff --git a/src/libcharon/plugins/tnc_imv/Makefile.in b/src/libcharon/plugins/tnc_imv/Makefile.in index cf58f0dc3..13b011101 100644 --- a/src/libcharon/plugins/tnc_imv/Makefile.in +++ b/src/libcharon/plugins/tnc_imv/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_tnc_imv_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_tnc_imv_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnc_imv_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c index b1da73156..0985a47a8 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv_manager.c @@ -241,7 +241,7 @@ METHOD(imv_manager_t, enforce_recommendation, bool, return FALSE; } else - { + { auth = ike_sa->get_auth_cfg(ike_sa, FALSE); id = identification_create_from_string(group); auth->add(auth, AUTH_RULE_GROUP, id); @@ -452,7 +452,8 @@ imv_manager_t* tnc_imv_manager_create(void) policy = enum_from_name(recommendation_policy_names, lib->settings->get_str(lib->settings, - "charon.plugins.tnc-imv.recommendation_policy", "default")); + "%s.plugins.tnc-imv.recommendation_policy", "default", + charon->name)); this->policy = (policy != -1) ? policy : RECOMMENDATION_POLICY_DEFAULT; DBG1(DBG_TNC, "TNC recommendation policy is '%N'", recommendation_policy_names, this->policy); diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_plugin.c b/src/libcharon/plugins/tnc_imv/tnc_imv_plugin.c index c16f6b9e1..612c98add 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv_plugin.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv_plugin.c @@ -47,6 +47,8 @@ METHOD(plugin_t, get_features, int, PLUGIN_CALLBACK(tnc_manager_register, tnc_imv_manager_create), PLUGIN_PROVIDE(CUSTOM, "imv-manager"), PLUGIN_DEPENDS(CUSTOM, "tnccs-manager"), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), + PLUGIN_SDEPEND(CERT_DECODE, CERT_TRUSTED_PUBKEY), }; *features = f; return countof(f); diff --git a/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c b/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c index 7843293a1..396d5d854 100644 --- a/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c +++ b/src/libcharon/plugins/tnc_imv/tnc_imv_recommendations.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2010-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -123,8 +124,13 @@ METHOD(recommendations_t, have_recommendation, bool, TNC_IMV_Evaluation_Result final_eval; bool first = TRUE, incomplete = FALSE; - *rec = final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; - *eval = final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + final_rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + final_eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + if (rec && eval) + { + *rec = final_rec; + *eval = final_eval; + } if (this->recs->get_count(this->recs) == 0) { @@ -267,11 +273,32 @@ METHOD(recommendations_t, have_recommendation, bool, { return FALSE; } - *rec = final_rec; - *eval = final_eval; + if (rec && eval) + { + *rec = final_rec; + *eval = final_eval; + } return TRUE; } +METHOD(recommendations_t, clear_recommendation, void, + private_tnc_imv_recommendations_t *this) +{ + enumerator_t *enumerator; + recommendation_entry_t *entry; + + enumerator = this->recs->create_enumerator(this->recs); + while (enumerator->enumerate(enumerator, &entry)) + { + entry->have_recommendation = FALSE; + entry->rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; + entry->eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + chunk_clear(&entry->reason); + chunk_clear(&entry->reason_language); + } + enumerator->destroy(enumerator); +} + METHOD(recommendations_t, get_preferred_language, chunk_t, private_tnc_imv_recommendations_t *this) { @@ -293,7 +320,7 @@ METHOD(recommendations_t, set_reason_string, TNC_Result, bool found = FALSE; DBG2(DBG_TNC, "IMV %u is setting reason string to '%.*s'", - id, reason.len, reason.ptr); + id, (int)reason.len, reason.ptr); enumerator = this->recs->create_enumerator(this->recs); while (enumerator->enumerate(enumerator, &entry)) @@ -318,7 +345,7 @@ METHOD(recommendations_t, set_reason_language, TNC_Result, bool found = FALSE; DBG2(DBG_TNC, "IMV %u is setting reason language to '%.*s'", - id, reason_lang.len, reason_lang.ptr); + id, (int)reason_lang.len, reason_lang.ptr); enumerator = this->recs->create_enumerator(this->recs); while (enumerator->enumerate(enumerator, &entry)) @@ -362,21 +389,6 @@ METHOD(recommendations_t, create_reason_enumerator, enumerator_t*, (void*)reason_filter, NULL, NULL); } -METHOD(recommendations_t, clear_reasons, void, - private_tnc_imv_recommendations_t *this) -{ - enumerator_t *enumerator; - recommendation_entry_t *entry; - - enumerator = this->recs->create_enumerator(this->recs); - while (enumerator->enumerate(enumerator, &entry)) - { - chunk_clear(&entry->reason); - chunk_clear(&entry->reason_language); - } - enumerator->destroy(enumerator); -} - METHOD(recommendations_t, destroy, void, private_tnc_imv_recommendations_t *this) { @@ -407,12 +419,12 @@ recommendations_t* tnc_imv_recommendations_create(linked_list_t *imv_list) .public = { .provide_recommendation = _provide_recommendation, .have_recommendation = _have_recommendation, + .clear_recommendation = _clear_recommendation, .get_preferred_language = _get_preferred_language, .set_preferred_language = _set_preferred_language, .set_reason_string = _set_reason_string, .set_reason_language = _set_reason_language, .create_reason_enumerator = _create_reason_enumerator, - .clear_reasons = _clear_reasons, .destroy = _destroy, }, .recs = linked_list_create(), diff --git a/src/libcharon/plugins/tnc_pdp/Makefile.in b/src/libcharon/plugins/tnc_pdp/Makefile.in index 70d3d6249..2b3fbd42b 100644 --- a/src/libcharon/plugins/tnc_pdp/Makefile.in +++ b/src/libcharon/plugins/tnc_pdp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_tnc_pdp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_tnc_pdp_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnc_pdp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c index 0625baa90..77eaa0e05 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include typedef struct private_tnc_pdp_t private_tnc_pdp_t; @@ -66,11 +66,6 @@ struct private_tnc_pdp_t { */ int ipv6; - /** - * Callback job dispatching commands - */ - callback_job_t *job; - /** * RADIUS shared secret */ @@ -87,9 +82,9 @@ struct private_tnc_pdp_t { signer_t *signer; /** - * Random number generator for MS-MPPE salt values + * Nonce generator for MS-MPPE salt values */ - rng_t *rng; + nonce_gen_t *ng; /** * List of registered TNC-PDP connections @@ -221,7 +216,11 @@ static chunk_t encrypt_mppe_key(private_tnc_pdp_t *this, u_int8_t type, a = chunk_create((u_char*)&(mppe_key->salt), sizeof(mppe_key->salt)); do { - this->rng->get_bytes(this->rng, a.len, a.ptr); + if (!this->ng->get_nonce(this->ng, a.len, a.ptr)) + { + free(data.ptr); + return chunk_empty; + } *a.ptr |= 0x80; } while (mppe_key->salt == *salt); @@ -236,8 +235,12 @@ static chunk_t encrypt_mppe_key(private_tnc_pdp_t *this, u_int8_t type, while (c < data.ptr + data.len) { /* b(i) = MD5(S + c(i-1)) */ - this->hasher->get_hash(this->hasher, this->secret, NULL); - this->hasher->get_hash(this->hasher, seed, b); + if (!this->hasher->get_hash(this->hasher, this->secret, NULL) || + !this->hasher->get_hash(this->hasher, seed, b)) + { + free(data.ptr); + return chunk_empty; + } /* c(i) = b(i) xor p(1) */ memxor(c, b, HASH_SIZE_MD5); @@ -263,20 +266,18 @@ static void send_response(private_tnc_pdp_t *this, radius_message_t *request, u_int16_t salt = 0; response = radius_message_create(code); - if (eap) - { - data = eap->get_data(eap); - DBG3(DBG_CFG, "%N payload %B", eap_type_names, this->type, &data); + data = eap->get_data(eap); + DBG3(DBG_CFG, "%N payload %B", eap_type_names, this->type, &data); - /* fragment data suitable for RADIUS */ - while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE) - { - response->add(response, RAT_EAP_MESSAGE, - chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE)); - data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE); - } - response->add(response, RAT_EAP_MESSAGE, data); + /* fragment data suitable for RADIUS */ + while (data.len > MAX_RADIUS_ATTRIBUTE_SIZE) + { + response->add(response, RAT_EAP_MESSAGE, + chunk_create(data.ptr, MAX_RADIUS_ATTRIBUTE_SIZE)); + data = chunk_skip(data, MAX_RADIUS_ATTRIBUTE_SIZE); } + response->add(response, RAT_EAP_MESSAGE, data); + if (group) { tunnel_type = RADIUS_TUNNEL_TYPE_ESP; @@ -291,19 +292,20 @@ static void send_response(private_tnc_pdp_t *this, radius_message_t *request, data = encrypt_mppe_key(this, MS_MPPE_RECV_KEY, recv, &salt, request); response->add(response, RAT_VENDOR_SPECIFIC, data); chunk_free(&data); - + send = chunk_create(msk.ptr + recv.len, msk.len - recv.len); data = encrypt_mppe_key(this, MS_MPPE_SEND_KEY, send, &salt, request); response->add(response, RAT_VENDOR_SPECIFIC, data); chunk_free(&data); } response->set_identifier(response, request->get_identifier(request)); - response->sign(response, request->get_authenticator(request), - this->secret, this->hasher, this->signer, NULL, TRUE); - - DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", radius_message_code_names, - code, client); - send_message(this, response, client); + if (response->sign(response, request->get_authenticator(request), + this->secret, this->hasher, this->signer, NULL, TRUE)) + { + DBG1(DBG_CFG, "sending RADIUS %N to client '%H'", + radius_message_code_names, code, client); + send_message(this, response, client); + } response->destroy(response); } @@ -368,7 +370,7 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request, eap_identity = chunk_create(message.ptr + 5, message.len - 5); peer = identification_create_from_data(eap_identity); method = charon->eap->create_instance(charon->eap, this->type, - 0, EAP_SERVER, this->server, peer); + 0, EAP_SERVER, this->server, peer); if (!method) { peer->destroy(peer); @@ -524,7 +526,7 @@ static job_requeue_t receive(private_tnc_pdp_t *this) if (request) { DBG1(DBG_CFG, "received RADIUS %N from client '%H'", - radius_message_code_names, request->get_code(request), source); + radius_message_code_names, request->get_code(request), source); if (request->verify(request, NULL, this->secret, this->hasher, this->signer)) @@ -532,7 +534,7 @@ static job_requeue_t receive(private_tnc_pdp_t *this) process_eap(this, request, source); } request->destroy(request); - + } else { @@ -546,10 +548,6 @@ static job_requeue_t receive(private_tnc_pdp_t *this) METHOD(tnc_pdp_t, destroy, void, private_tnc_pdp_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } if (this->ipv4) { close(this->ipv4); @@ -561,7 +559,7 @@ METHOD(tnc_pdp_t, destroy, void, DESTROY_IF(this->server); DESTROY_IF(this->signer); DESTROY_IF(this->hasher); - DESTROY_IF(this->rng); + DESTROY_IF(this->ng); DESTROY_IF(this->connections); free(this); } @@ -582,13 +580,13 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) .ipv6 = open_socket(AF_INET6, port), .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5), .signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128), - .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), + .ng = lib->crypto->create_nonce_gen(lib->crypto), .connections = tnc_pdp_connections_create(), ); - if (!this->hasher || !this->signer || !this->rng) + if (!this->hasher || !this->signer || !this->ng) { - DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required"); + DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/NG required"); destroy(this); return NULL; } @@ -608,7 +606,7 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) } server = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-pdp.server", NULL); + "%s.plugins.tnc-pdp.server", NULL, charon->name); if (!server) { DBG1(DBG_CFG, "missing PDP server name, PDP disabled"); @@ -618,7 +616,7 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) this->server = identification_create_from_string(server); secret = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-pdp.secret", NULL); + "%s.plugins.tnc-pdp.secret", NULL, charon->name); if (!secret) { DBG1(DBG_CFG, "missing RADIUS secret, PDP disabled"); @@ -626,10 +624,15 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) return NULL; } this->secret = chunk_create(secret, strlen(secret)); - this->signer->set_key(this->signer, this->secret); + if (!this->signer->set_key(this->signer, this->secret)) + { + DBG1(DBG_CFG, "could not set signer key"); + destroy(this); + return NULL; + } eap_type_str = lib->settings->get_str(lib->settings, - "charon.plugins.tnc-pdp.method", "ttls"); + "%s.plugins.tnc-pdp.method", "ttls", charon->name); this->type = eap_type_from_string(eap_type_str); if (this->type == 0) { @@ -639,9 +642,9 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port) } DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type); - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c index 175a57aba..bca43985f 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c @@ -33,7 +33,7 @@ struct private_tnc_pdp_connections_t { /** * List of TNC PEP RADIUS Connections - */ + */ linked_list_t *list; }; @@ -94,13 +94,14 @@ static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op) if (nas_id.len) { DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s' NAS '%.*s'", - not ? "could not find" : op, user_name.len, user_name.ptr, - nas_id.len, nas_id.ptr); + not ? "could not find" : op, (int)user_name.len, + user_name.ptr, (int)nas_id.len, nas_id.ptr); } else { - DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'", - not ? "could not find" : op, user_name.len, user_name.ptr); + DBG1(DBG_CFG, "%s RADIUS connection for user '%.*s'", + not ? "could not find" : op, (int)user_name.len, + user_name.ptr); } } @@ -114,8 +115,8 @@ METHOD(tnc_pdp_connections_t, add, void, ike_sa_t *ike_sa; bool found = FALSE; - ike_sa_id = ike_sa_id_create(0, 0, FALSE); - ike_sa = ike_sa_create(ike_sa_id); + ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0, FALSE); + ike_sa = ike_sa_create(ike_sa_id, FALSE, IKEV2); ike_sa_id->destroy(ike_sa_id); ike_sa->set_other_id(ike_sa, peer); @@ -134,7 +135,7 @@ METHOD(tnc_pdp_connections_t, add, void, } } enumerator->destroy(enumerator); - + if (!found) { entry = malloc_thing(entry_t); diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h index b9f5d097b..16492020e 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h @@ -25,7 +25,7 @@ typedef struct tnc_pdp_connections_t tnc_pdp_connections_t; #include #include -#include +#include /** * Public interface of a tnc_pdp_connections object diff --git a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c index 9abe02aec..295c7a5d6 100644 --- a/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c +++ b/src/libcharon/plugins/tnc_pdp/tnc_pdp_plugin.c @@ -16,6 +16,8 @@ #include "tnc_pdp_plugin.h" #include "tnc_pdp.h" +#include + typedef struct private_tnc_pdp_plugin_t private_tnc_pdp_plugin_t; /** @@ -73,7 +75,7 @@ plugin_t *tnc_pdp_plugin_create() int port; port = lib->settings->get_int(lib->settings, - "charon.plugins.tnc_pdp.port", RADIUS_PORT); + "%s.plugins.tnc_pdp.port", RADIUS_PORT, charon->name); INIT(this, .public = { diff --git a/src/libcharon/plugins/tnc_tnccs/Makefile.in b/src/libcharon/plugins/tnc_tnccs/Makefile.in index c12a837d1..3ef913e7b 100644 --- a/src/libcharon/plugins/tnc_tnccs/Makefile.in +++ b/src/libcharon/plugins/tnc_tnccs/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_tnc_tnccs_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_tnc_tnccs_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnc_tnccs_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c index 64ed160d9..515e85804 100644 --- a/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c +++ b/src/libcharon/plugins/tnc_tnccs/tnc_tnccs_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -74,6 +74,11 @@ struct tnccs_connection_entry_t { */ bool *request_handshake_retry; + /** + * Maximum size of a PA-TNC message + */ + u_int32_t max_msg_len; + /** * collection of IMV recommendations */ @@ -181,7 +186,7 @@ METHOD(tnccs_manager_t, create_instance, tnccs_t*, METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID, private_tnc_tnccs_manager_t *this, tnccs_type_t type, tnccs_t *tnccs, tnccs_send_message_t send_message, bool* request_handshake_retry, - recommendations_t **recs) + u_int32_t max_msg_len, recommendations_t **recs) { tnccs_connection_entry_t *entry; @@ -190,6 +195,7 @@ METHOD(tnccs_manager_t, create_connection, TNC_ConnectionID, entry->tnccs = tnccs; entry->send_message = send_message; entry->request_handshake_retry = request_handshake_retry; + entry->max_msg_len = max_msg_len; if (recs) { /* we assume a TNC Server needing recommendations from IMVs */ @@ -564,16 +570,18 @@ METHOD(tnccs_manager_t, get_attribute, TNC_Result, return TNC_RESULT_SUCCESS; } case TNC_ATTRIBUTEID_MAX_ROUND_TRIPS: - return uint_attribute(buffer_len, buffer, value_len, 0xffffffff); + return uint_attribute(buffer_len, buffer, value_len, + 0xffffffff); case TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE: - return uint_attribute(buffer_len, buffer, value_len, 0x00000000); + return uint_attribute(buffer_len, buffer, value_len, + entry->max_msg_len); case TNC_ATTRIBUTEID_HAS_LONG_TYPES: case TNC_ATTRIBUTEID_HAS_EXCLUSIVE: return bool_attribute(buffer_len, buffer, value_len, - entry->type == TNCCS_2_0); + entry->type == TNCCS_2_0); case TNC_ATTRIBUTEID_HAS_SOH: return bool_attribute(buffer_len, buffer, value_len, - entry->type == TNCCS_SOH); + entry->type == TNCCS_SOH); case TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL: { char *protocol; diff --git a/src/libcharon/plugins/tnccs_11/Makefile.am b/src/libcharon/plugins/tnccs_11/Makefile.am index c205692d4..1d29460f8 100644 --- a/src/libcharon/plugins/tnccs_11/Makefile.am +++ b/src/libcharon/plugins/tnccs_11/Makefile.am @@ -1,6 +1,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs \ diff --git a/src/libcharon/plugins/tnccs_11/Makefile.in b/src/libcharon/plugins/tnccs_11/Makefile.in index 1902d1f93..3a506e672 100644 --- a/src/libcharon/plugins/tnccs_11/Makefile.in +++ b/src/libcharon/plugins/tnccs_11/Makefile.in @@ -53,6 +53,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -94,7 +95,7 @@ libstrongswan_tnccs_11_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_tnccs_11_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnccs_11_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -120,6 +121,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -214,11 +216,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -235,11 +240,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -255,6 +261,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -264,7 +271,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -294,6 +300,8 @@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs \ diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.c b/src/libcharon/plugins/tnccs_11/tnccs_11.c index 3673221e5..56858a8b4 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11.c +++ b/src/libcharon/plugins/tnccs_11/tnccs_11.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include #include +#include #include typedef struct private_tnccs_11_t private_tnccs_11_t; @@ -66,6 +67,11 @@ struct private_tnccs_11_t { */ tnccs_batch_t *batch; + /** + * Maximum PA-TNC message size + */ + size_t max_msg_len; + /** * Mutex locking the batch in construction */ @@ -122,7 +128,7 @@ METHOD(tnccs_t, send_msg, TNC_Result, return TNC_RESULT_NO_LONG_MESSAGE_TYPES; } msg_type = (msg_vid << 8) | msg_subtype; - + pa_subtype_names = get_pa_subtype_names(msg_vid); if (pa_subtype_names) { @@ -266,10 +272,10 @@ static void handle_message(private_tnccs_11_t *this, tnccs_msg_t *msg) reason_msg = (tnccs_reason_strings_msg_t*)msg; reason_string = reason_msg->get_reason(reason_msg, &reason_lang); - DBG2(DBG_TNC, "reason string is '%.*s'", reason_string.len, - reason_string.ptr); - DBG2(DBG_TNC, "reason language is '%.*s'", reason_lang.len, - reason_lang.ptr); + DBG2(DBG_TNC, "reason string is '%.*s'", (int)reason_string.len, + reason_string.ptr); + DBG2(DBG_TNC, "language code is '%.*s'", (int)reason_lang.len, + reason_lang.ptr); break; } default: @@ -289,8 +295,9 @@ METHOD(tls_t, process, status_t, if (this->is_server && !this->connection_id) { this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_1_1, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, &this->recs); + TNCCS_1_1, (tnccs_t*)this, _send_msg, + &this->request_handshake_retry, + this->max_msg_len, &this->recs); if (!this->connection_id) { return FAILED; @@ -304,7 +311,7 @@ METHOD(tls_t, process, status_t, data = chunk_create(buf, buflen); DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u", data.len, this->connection_id); - DBG3(DBG_TNC, "%.*s", data.len, data.ptr); + DBG3(DBG_TNC, "%.*s", (int)data.len, data.ptr); batch = tnccs_batch_create_from_data(this->is_server, ++this->batch_id, data); status = batch->process(batch); @@ -396,7 +403,6 @@ static void check_and_build_recommendation(private_tnccs_11_t *this) this->batch->add_msg(this->batch, msg); } enumerator->destroy(enumerator); - this->recs->clear_reasons(this->recs); /* we have reache the final state */ this->delete_state = TRUE; @@ -416,7 +422,8 @@ METHOD(tls_t, build, status_t, this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, TNCCS_1_1, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, NULL); + &this->request_handshake_retry, + this->max_msg_len, NULL); if (!this->connection_id) { return FAILED; @@ -456,8 +463,8 @@ METHOD(tls_t, build, status_t, data = this->batch->get_encoding(this->batch); DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u", data.len, this->connection_id); - DBG3(DBG_TNC, "%.*s", data.len, data.ptr); - *msglen = data.len; + DBG3(DBG_TNC, "%.*s", (int)data.len, data.ptr); + *msglen = 0; if (data.len > *buflen) { @@ -545,6 +552,9 @@ tls_t *tnccs_11_create(bool is_server) }, .is_server = is_server, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .max_msg_len = lib->settings->get_int(lib->settings, + "%s.plugins.tnccs-11.max_message_size", 45000, + charon->name), ); return &this->public; diff --git a/src/libcharon/plugins/tnccs_20/Makefile.am b/src/libcharon/plugins/tnccs_20/Makefile.am index ec17e6412..da924b412 100644 --- a/src/libcharon/plugins/tnccs_20/Makefile.am +++ b/src/libcharon/plugins/tnccs_20/Makefile.am @@ -1,6 +1,8 @@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs diff --git a/src/libcharon/plugins/tnccs_20/Makefile.in b/src/libcharon/plugins/tnccs_20/Makefile.in index b0078f338..26d26dbd9 100644 --- a/src/libcharon/plugins/tnccs_20/Makefile.in +++ b/src/libcharon/plugins/tnccs_20/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -92,7 +93,7 @@ libstrongswan_tnccs_20_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_tnccs_20_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnccs_20_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -118,6 +119,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -212,11 +214,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -233,11 +238,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -253,6 +259,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -262,7 +269,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -292,6 +298,8 @@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ INCLUDES = \ -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libcharon \ + -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libtls \ -I$(top_srcdir)/src/libtncif \ -I$(top_srcdir)/src/libtnccs diff --git a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c index c6a4bb599..2f932637a 100644 --- a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c +++ b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -95,6 +95,16 @@ struct private_pb_tnc_batch_t { */ pb_tnc_batch_type_t type; + /** + * Current PB-TNC Batch size + */ + size_t batch_len; + + /** + * Maximum PB-TNC Batch size + */ + size_t max_batch_len; + /** * linked list of PB-TNC messages */ @@ -128,42 +138,46 @@ METHOD(pb_tnc_batch_t, get_encoding, chunk_t, return this->encoding; } -METHOD(pb_tnc_batch_t, add_msg, void, +METHOD(pb_tnc_batch_t, add_msg, bool, private_pb_tnc_batch_t *this, pb_tnc_msg_t* msg) { + chunk_t msg_value; + size_t msg_len; + + msg->build(msg); + msg_value = msg->get_encoding(msg); + msg_len = PB_TNC_HEADER_SIZE + msg_value.len; + + if (this->batch_len + msg_len > this->max_batch_len) + { + /* message just does not fit into this batch */ + return FALSE; + } + this->batch_len += msg_len; + DBG2(DBG_TNC, "adding %N message", pb_tnc_msg_type_names, msg->get_type(msg)); this->messages->insert_last(this->messages, msg); + return TRUE; } METHOD(pb_tnc_batch_t, build, void, private_pb_tnc_batch_t *this) { - u_int32_t batch_len, msg_len; + u_int32_t msg_len; chunk_t msg_value; enumerator_t *enumerator; pb_tnc_msg_type_t msg_type; pb_tnc_msg_t *msg; bio_writer_t *writer; - /* compute total PB-TNC batch size by summing over all messages */ - batch_len = PB_TNC_BATCH_HEADER_SIZE; - enumerator = this->messages->create_enumerator(this->messages); - while (enumerator->enumerate(enumerator, &msg)) - { - msg->build(msg); - msg_value = msg->get_encoding(msg); - batch_len += PB_TNC_HEADER_SIZE + msg_value.len; - } - enumerator->destroy(enumerator); - /* build PB-TNC batch header */ - writer = bio_writer_create(batch_len); + writer = bio_writer_create(this->batch_len); writer->write_uint8 (writer, PB_TNC_VERSION); writer->write_uint8 (writer, this->is_server ? PB_TNC_BATCH_FLAG_D : PB_TNC_BATCH_FLAG_NONE); writer->write_uint16(writer, this->type); - writer->write_uint32(writer, batch_len); + writer->write_uint32(writer, this->batch_len); /* build PB-TNC messages */ enumerator = this->messages->create_enumerator(this->messages); @@ -221,7 +235,7 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, /* Version */ if (version != PB_TNC_VERSION) { - DBG1(DBG_TNC, "unsupported TNCCS batch version 0x%01x", version); + DBG1(DBG_TNC, "unsupported TNCCS batch version 0x%02x", version); msg = pb_error_msg_create(TRUE, PEN_IETF, PB_ERROR_VERSION_NOT_SUPPORTED); err_msg = (pb_error_msg_t*)msg; @@ -258,6 +272,8 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, PB_ERROR_UNEXPECTED_BATCH_TYPE); goto fatal; } + DBG1(DBG_TNC, "processing PB-TNC %N batch", pb_tnc_batch_type_names, + this->type); /* Batch Length */ if (this->encoding.len != batch_len) @@ -270,6 +286,13 @@ static status_t process_batch_header(private_pb_tnc_batch_t *this, } this->offset = PB_TNC_BATCH_HEADER_SIZE; + + /* Register an empty CDATA batch with the state machine */ + if (this->type == PB_BATCH_CDATA) + { + state_machine->set_empty_cdata(state_machine, + this->offset == this->encoding.len); + } return SUCCESS; fatal: @@ -445,8 +468,7 @@ METHOD(pb_tnc_batch_t, process, status_t, { return FAILED; } - DBG1(DBG_TNC, "processing PB-TNC %N batch", pb_tnc_batch_type_names, - this->type); + while (this->offset < this->encoding.len) { switch (process_tnc_msg(this)) @@ -490,7 +512,8 @@ METHOD(pb_tnc_batch_t, destroy, void, /** * See header */ -pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type) +pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, + size_t max_batch_len) { private_pb_tnc_batch_t *this; @@ -507,6 +530,8 @@ pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type) }, .is_server = is_server, .type = type, + .max_batch_len = max_batch_len, + .batch_len = PB_TNC_BATCH_HEADER_SIZE, .messages = linked_list_create(), .errors = linked_list_create(), ); diff --git a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h index 17e5fff4c..60cef7735 100644 --- a/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h +++ b/src/libcharon/plugins/tnccs_20/batch/pb_tnc_batch.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ typedef struct pb_tnc_batch_t pb_tnc_batch_t; * PB-TNC Batch Types as defined in section 4.1 of RFC 5793 */ enum pb_tnc_batch_type_t { + PB_BATCH_NONE = 0, /* for internal use only */ PB_BATCH_CDATA = 1, PB_BATCH_SDATA = 2, PB_BATCH_RESULT = 3, @@ -70,8 +71,9 @@ struct pb_tnc_batch_t { * Add a PB-TNC Message * * @param msg PB-TNC message to be addedd + * @return TRUE if message fit into batch and was added */ - void (*add_msg)(pb_tnc_batch_t *this, pb_tnc_msg_t* msg); + bool (*add_msg)(pb_tnc_batch_t *this, pb_tnc_msg_t* msg); /** * Build the PB-TNC Batch @@ -112,8 +114,10 @@ struct pb_tnc_batch_t { * * @param is_server TRUE if server, FALSE if client * @param type PB-TNC batch type + * @param max_batch_len maximum size the PB-TNC batch */ -pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type); +pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, + size_t max_batch_len); /** * Create an unprocessed PB-TNC Batch from data diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c index fa3deddf6..974db4d70 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_access_recommendation_msg.c @@ -82,11 +82,13 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(ACCESS_RECOMMENDATION_MSG_SIZE); writer->write_uint16(writer, ACCESS_RECOMMENDATION_RESERVED); writer->write_uint16(writer, this->recommendation); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -98,7 +100,6 @@ METHOD(pb_tnc_msg_t, process, status_t, bio_reader_t *reader; u_int16_t reserved; - /* process message */ reader = bio_reader_create(this->encoding); reader->read_uint16(reader, &reserved); reader->read_uint16(reader, &this->recommendation); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c index 0d558c0d4..ee06575b4 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_assessment_result_msg.c @@ -78,10 +78,12 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(ASSESSMENT_RESULT_MSG_SIZE); writer->write_uint32(writer, this->assessment_result); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -92,7 +94,6 @@ METHOD(pb_tnc_msg_t, process, status_t, { bio_reader_t *reader; - /* process message */ reader = bio_reader_create(this->encoding); reader->read_uint32(reader, &this->assessment_result); reader->destroy(reader); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c index 03e3cec92..457d3da21 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c @@ -120,6 +120,11 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; + if (this->encoding.ptr) + { + return; + } + /* build message header */ writer = bio_writer_create(ERROR_HEADER_SIZE); writer->write_uint8 (writer, this->fatal ? @@ -142,8 +147,6 @@ METHOD(pb_tnc_msg_t, build, void, /* Error Offset */ writer->write_uint32(writer, this->error_offset); } - - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c index 297cc8df7..46df54486 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_language_preference_msg.c @@ -75,6 +75,10 @@ METHOD(pb_tnc_msg_t, get_encoding, chunk_t, METHOD(pb_tnc_msg_t, build, void, private_pb_language_preference_msg_t *this) { + if (this->encoding.ptr) + { + return; + } this->encoding = chunk_cat("cc", chunk_create(PB_LANG_PREFIX, PB_LANG_PREFIX_LEN), this->language_preference); diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c index 1c4913e5e..bbad9bf55 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.c @@ -68,14 +68,9 @@ struct private_pb_pa_msg_t { bool excl; /** - * PA Message Vendor ID + * Vendor-specific PA Subtype */ - u_int32_t vendor_id; - - /** - * PA Subtype - */ - u_int32_t subtype; + pen_type_t subtype; /** * Posture Validator Identifier @@ -116,17 +111,21 @@ METHOD(pb_tnc_msg_t, build, void, chunk_t msg_header; bio_writer_t *writer; + if (this->encoding.ptr) + { + return; + } + /* build message header */ writer = bio_writer_create(64); writer->write_uint8 (writer, this->excl ? PA_FLAG_EXCL : PA_FLAG_NONE); - writer->write_uint24(writer, this->vendor_id); - writer->write_uint32(writer, this->subtype); + writer->write_uint24(writer, this->subtype.vendor_id); + writer->write_uint32(writer, this->subtype.type); writer->write_uint16(writer, this->collector_id); writer->write_uint16(writer, this->validator_id); msg_header = writer->get_buf(writer); /* create encoding by concatenating message header and message body */ - free(this->encoding.ptr); this->encoding = chunk_cat("cc", msg_header, this->msg_body); writer->destroy(writer); } @@ -141,8 +140,8 @@ METHOD(pb_tnc_msg_t, process, status_t, /* process message header */ reader = bio_reader_create(this->encoding); reader->read_uint8 (reader, &flags); - reader->read_uint24(reader, &this->vendor_id); - reader->read_uint32(reader, &this->subtype); + reader->read_uint24(reader, &this->subtype.vendor_id); + reader->read_uint32(reader, &this->subtype.type); reader->read_uint16(reader, &this->collector_id); reader->read_uint16(reader, &this->validator_id); this->excl = ((flags & PA_FLAG_EXCL) != PA_FLAG_NONE); @@ -156,14 +155,14 @@ METHOD(pb_tnc_msg_t, process, status_t, } reader->destroy(reader); - if (this->vendor_id == PEN_RESERVED) + if (this->subtype.vendor_id == PEN_RESERVED) { DBG1(DBG_TNC, "Vendor ID 0x%06x is reserved", PEN_RESERVED); *offset = 1; return FAILED; } - if (this->subtype == PA_RESERVED_SUBTYPE) + if (this->subtype.type == PA_RESERVED_SUBTYPE) { DBG1(DBG_TNC, "PA Subtype 0x%08x is reserved", PA_RESERVED_SUBTYPE); *offset = 4; @@ -180,11 +179,10 @@ METHOD(pb_tnc_msg_t, destroy, void, free(this); } -METHOD(pb_pa_msg_t, get_vendor_id, u_int32_t, - private_pb_pa_msg_t *this, u_int32_t *subtype) +METHOD(pb_pa_msg_t, get_subtype, pen_type_t, + private_pb_pa_msg_t *this) { - *subtype = this->subtype; - return this->vendor_id; + return this->subtype; } METHOD(pb_pa_msg_t, get_collector_id, u_int16_t, @@ -226,7 +224,7 @@ pb_tnc_msg_t *pb_pa_msg_create_from_data(chunk_t data) .process = _process, .destroy = _destroy, }, - .get_vendor_id = _get_vendor_id, + .get_subtype = _get_subtype, .get_collector_id = _get_collector_id, .get_validator_id = _get_validator_id, .get_body = _get_body, @@ -257,15 +255,14 @@ pb_tnc_msg_t *pb_pa_msg_create(u_int32_t vendor_id, u_int32_t subtype, .process = _process, .destroy = _destroy, }, - .get_vendor_id = _get_vendor_id, + .get_subtype= _get_subtype, .get_collector_id = _get_collector_id, .get_validator_id = _get_validator_id, .get_body = _get_body, .get_exclusive_flag = _get_exclusive_flag, }, .type = PB_MSG_PA, - .vendor_id = vendor_id, - .subtype = subtype, + .subtype = { vendor_id, subtype }, .collector_id = collector_id, .validator_id = validator_id, .excl = excl, diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h index d9db9a1ce..5c9b7c0bf 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h +++ b/src/libcharon/plugins/tnccs_20/messages/pb_pa_msg.h @@ -25,6 +25,8 @@ typedef struct pb_pa_msg_t pb_pa_msg_t; #include "pb_tnc_msg.h" +#include + /** * Class representing the PB-PA message type. */ @@ -38,10 +40,9 @@ struct pb_pa_msg_t { /** * Get PA Message Vendor ID and Subtype * - * @param subtype PA Subtype - * @return PA Message Vendor ID + * @return Vendor-specific PA Subtype */ - u_int32_t (*get_vendor_id)(pb_pa_msg_t *this, u_int32_t *subtype); + pen_type_t (*get_subtype)(pb_pa_msg_t *this); /** * Get Posture Collector ID diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c index 181ecf61b..511b45402 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_reason_string_msg.c @@ -83,12 +83,14 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(64); writer->write_data32(writer, this->reason_string); writer->write_data8 (writer, this->language_code); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); @@ -99,7 +101,6 @@ METHOD(pb_tnc_msg_t, process, status_t, { bio_reader_t *reader; - /* process message */ reader = bio_reader_create(this->encoding); if (!reader->read_data32(reader, &this->reason_string)) { diff --git a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c index d213db313..c853f03a3 100644 --- a/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c +++ b/src/libcharon/plugins/tnccs_20/messages/pb_remediation_parameters_msg.c @@ -108,14 +108,16 @@ METHOD(pb_tnc_msg_t, build, void, { bio_writer_t *writer; - /* build message */ + if (this->encoding.ptr) + { + return; + } writer = bio_writer_create(64); writer->write_uint32(writer, this->vendor_id); writer->write_uint32(writer, this->parameters_type); writer->write_data32(writer, this->remediation_string); writer->write_data8 (writer, this->language_code); - free(this->encoding.ptr); this->encoding = writer->get_buf(writer); this->encoding = chunk_clone(this->encoding); writer->destroy(writer); diff --git a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c index f0cf14ac1..5e95131a8 100644 --- a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c +++ b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.c @@ -70,6 +70,11 @@ struct private_pb_tnc_state_machine_t { */ bool is_server; + /** + * Informs whether last received PB-TNC CDATA Batch was empty + */ + bool empty_cdata; + /** * Current PB-TNC state */ @@ -265,6 +270,22 @@ METHOD(pb_tnc_state_machine_t, send_batch, bool, return TRUE; } +METHOD(pb_tnc_state_machine_t, get_empty_cdata, bool, + private_pb_tnc_state_machine_t *this) +{ + return this->empty_cdata; +} + +METHOD(pb_tnc_state_machine_t, set_empty_cdata, void, + private_pb_tnc_state_machine_t *this, bool empty) +{ + if (empty) + { + DBG2(DBG_TNC, "received empty PB-TNC CDATA batch"); + } + this->empty_cdata = empty; +} + METHOD(pb_tnc_state_machine_t, destroy, void, private_pb_tnc_state_machine_t *this) { @@ -283,6 +304,8 @@ pb_tnc_state_machine_t* pb_tnc_state_machine_create(bool is_server) .get_state = _get_state, .receive_batch = _receive_batch, .send_batch = _send_batch, + .get_empty_cdata = _get_empty_cdata, + .set_empty_cdata = _set_empty_cdata, .destroy = _destroy, }, .is_server = is_server, diff --git a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h index 8076b6ded..aa317041e 100644 --- a/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h +++ b/src/libcharon/plugins/tnccs_20/state_machine/pb_tnc_state_machine.h @@ -72,6 +72,20 @@ struct pb_tnc_state_machine_t { */ bool (*send_batch)(pb_tnc_state_machine_t *this, pb_tnc_batch_type_t type); + /** + * Informs whether the last received PB-TNC CDATA Batch was empty + * + * @result TRUE if last received PB-TNC CDATA Batch was empty + */ + bool (*get_empty_cdata)(pb_tnc_state_machine_t *this); + + /** + * Store information whether the received PB-TNC CDATA Batch was empty + * + * @param empty set to TRUE if received PB-TNC CDATA Batch was empty + */ + void (*set_empty_cdata)(pb_tnc_state_machine_t *this, bool empty); + /** * Destroys a pb_tnc_state_machine_t object. */ diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c index 606fc529b..44e1d278f 100644 --- a/src/libcharon/plugins/tnccs_20/tnccs_20.c +++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2011 Andreas Steffen + * Copyright (C) 2010-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -35,7 +35,9 @@ #include #include +#include #include +#include #include typedef struct private_tnccs_20_t private_tnccs_20_t; @@ -66,9 +68,24 @@ struct private_tnccs_20_t { TNC_ConnectionID connection_id; /** - * PB-TNC batch being constructed + * PB-TNC messages to be sent */ - pb_tnc_batch_t *batch; + linked_list_t *messages; + + /** + * Type of PB-TNC batch being constructed + */ + pb_tnc_batch_type_t batch_type; + + /** + * Maximum PB-TNC batch size + */ + size_t max_batch_len; + + /** + * Maximum PA-TNC message size + */ + size_t max_msg_len; /** * Mutex locking the batch in construction @@ -97,6 +114,30 @@ struct private_tnccs_20_t { }; +/** + * If the batch type changes then delete all accumulated PB-TNC messages + */ +void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type) +{ + pb_tnc_msg_t *msg; + + if (batch_type != this->batch_type) + { + if (this->batch_type != PB_BATCH_NONE) + { + DBG1(DBG_TNC, "cancelling PB-TNC %N batch", + pb_tnc_batch_type_names, this->batch_type); + + while (this->messages->remove_last(this->messages, + (void**)&msg) == SUCCESS) + { + msg->destroy(msg); + } + } + this->batch_type = batch_type; + } +} + METHOD(tnccs_t, send_msg, TNC_Result, private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, TNC_UInt32 msg_flags, @@ -138,13 +179,13 @@ METHOD(tnccs_t, send_msg, TNC_Result, /* adding PA message to SDATA or CDATA batch only */ batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA; this->mutex->lock(this->mutex); - if (!this->batch) + if (this->batch_type == PB_BATCH_NONE) { - this->batch = pb_tnc_batch_create(this->is_server, batch_type); + this->batch_type = batch_type; } - if (this->batch->get_type(this->batch) == batch_type) + if (this->batch_type == batch_type) { - this->batch->add_msg(this->batch, pb_tnc_msg); + this->messages->insert_last(this->messages, pb_tnc_msg); } else { @@ -167,30 +208,31 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) case PB_MSG_PA: { pb_pa_msg_t *pa_msg; - u_int32_t msg_vid, msg_subtype; + pen_type_t msg_subtype; u_int16_t imc_id, imv_id; chunk_t msg_body; bool excl; enum_name_t *pa_subtype_names; pa_msg = (pb_pa_msg_t*)msg; - msg_vid = pa_msg->get_vendor_id(pa_msg, &msg_subtype); + msg_subtype = pa_msg->get_subtype(pa_msg); msg_body = pa_msg->get_body(pa_msg); imc_id = pa_msg->get_collector_id(pa_msg); imv_id = pa_msg->get_validator_id(pa_msg); excl = pa_msg->get_exclusive_flag(pa_msg); - pa_subtype_names = get_pa_subtype_names(msg_vid); + pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id); if (pa_subtype_names) { DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", - pen_names, msg_vid, pa_subtype_names, msg_subtype, - msg_vid, msg_subtype); + pen_names, msg_subtype.vendor_id, pa_subtype_names, + msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type); } else { DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x", - pen_names, msg_vid, msg_vid, msg_subtype); + pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id, + msg_subtype.type); } this->send_msg = TRUE; @@ -198,13 +240,15 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) { tnc->imvs->receive_message(tnc->imvs, this->connection_id, excl, msg_body.ptr, msg_body.len, - msg_vid, msg_subtype, imc_id, imv_id); + msg_subtype.vendor_id, + msg_subtype.type, imc_id, imv_id); } else { tnc->imcs->receive_message(tnc->imcs, this->connection_id, excl, msg_body.ptr, msg_body.len, - msg_vid, msg_subtype, imv_id, imc_id); + msg_subtype.vendor_id, + msg_subtype.type, imv_id, imc_id); } this->send_msg = FALSE; break; @@ -313,7 +357,7 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) lang = lang_msg->get_language_preference(lang_msg); DBG2(DBG_TNC, "setting language preference to '%.*s'", - lang.len, lang.ptr); + (int)lang.len, lang.ptr); this->recs->set_preferred_language(this->recs, lang); break; } @@ -325,9 +369,9 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) reason_msg = (pb_reason_string_msg_t*)msg; reason_string = reason_msg->get_reason_string(reason_msg); language_code = reason_msg->get_language_code(reason_msg); - DBG2(DBG_TNC, "reason string is '%.*s'", reason_string.len, + DBG2(DBG_TNC, "reason string is '%.*s'", (int)reason_string.len, reason_string.ptr); - DBG2(DBG_TNC, "language code is '%.*s'", language_code.len, + DBG2(DBG_TNC, "language code is '%.*s'", (int)language_code.len, language_code.ptr); break; } @@ -344,23 +388,20 @@ static void build_retry_batch(private_tnccs_20_t *this) pb_tnc_batch_type_t batch_retry_type; batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY; - if (this->batch) + if (this->batch_type == batch_retry_type) { - if (this->batch->get_type(this->batch) == batch_retry_type) - { - /* retry batch has already been created */ - return; - } - DBG1(DBG_TNC, "cancelling PB-TNC %N batch", - pb_tnc_batch_type_names, this->batch->get_type(this->batch)); - this->batch->destroy(this->batch); - } + /* retry batch has already been selected */ + return; + } + + change_batch_type(this, batch_retry_type); + if (this->is_server) { + this->recs->clear_recommendation(this->recs); tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); } - this->batch = pb_tnc_batch_create(this->is_server, batch_retry_type); } METHOD(tls_t, process, status_t, @@ -375,8 +416,9 @@ METHOD(tls_t, process, status_t, if (this->is_server && !this->connection_id) { this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, &this->recs); + TNCCS_2_0, (tnccs_t*)this, _send_msg, + &this->request_handshake_retry, + this->max_msg_len, &this->recs); if (!this->connection_id) { return FAILED; @@ -461,13 +503,7 @@ METHOD(tls_t, process, status_t, case FAILED: this->fatal_error = TRUE; this->mutex->lock(this->mutex); - if (this->batch) - { - DBG1(DBG_TNC, "cancelling PB-TNC %N batch", - pb_tnc_batch_type_names, this->batch->get_type(this->batch)); - this->batch->destroy(this->batch); - } - this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE); + change_batch_type(this, PB_BATCH_CLOSE); this->mutex->unlock(this->mutex); /* fall through to add error messages to outbound batch */ case VERIFY_ERROR: @@ -475,7 +511,7 @@ METHOD(tls_t, process, status_t, while (enumerator->enumerate(enumerator, &msg)) { this->mutex->lock(this->mutex); - this->batch->add_msg(this->batch, msg->get_ref(msg)); + this->messages->insert_last(this->messages, msg->get_ref(msg)); this->mutex->unlock(this->mutex); } enumerator->destroy(enumerator); @@ -508,10 +544,10 @@ static void check_and_build_recommendation(private_tnccs_20_t *this) } if (this->recs->have_recommendation(this->recs, &rec, &eval)) { - this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_RESULT); + this->batch_type = PB_BATCH_RESULT; msg = pb_assessment_result_msg_create(eval); - this->batch->add_msg(this->batch, msg); + this->messages->insert_last(this->messages, msg); /** * Map IMV Action Recommendation codes to PB Access Recommendation codes @@ -530,16 +566,15 @@ static void check_and_build_recommendation(private_tnccs_20_t *this) pb_rec = PB_REC_ACCESS_DENIED; } msg = pb_access_recommendation_msg_create(pb_rec); - this->batch->add_msg(this->batch, msg); + this->messages->insert_last(this->messages, msg); enumerator = this->recs->create_reason_enumerator(this->recs); while (enumerator->enumerate(enumerator, &id, &reason, &language)) { msg = pb_reason_string_msg_create(reason, language); - this->batch->add_msg(this->batch, msg); + this->messages->insert_last(this->messages, msg); } enumerator->destroy(enumerator); - this->recs->clear_reasons(this->recs); } } @@ -557,7 +592,8 @@ METHOD(tls_t, build, status_t, this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, NULL); + &this->request_handshake_retry, + this->max_msg_len, NULL); if (!this->connection_id) { return FAILED; @@ -568,8 +604,8 @@ METHOD(tls_t, build, status_t, msg = pb_language_preference_msg_create(chunk_create(pref_lang, strlen(pref_lang))); this->mutex->lock(this->mutex); - this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CDATA); - this->batch->add_msg(this->batch, msg); + this->batch_type = PB_BATCH_CDATA; + this->messages->insert_last(this->messages, msg); this->mutex->unlock(this->mutex); tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, @@ -583,7 +619,7 @@ METHOD(tls_t, build, status_t, state = this->state_machine->get_state(this->state_machine); - if (this->is_server && this->fatal_error && state == PB_STATE_END) + if (this->fatal_error && state == PB_STATE_END) { DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection"); return FAILED; @@ -603,66 +639,98 @@ METHOD(tls_t, build, status_t, this->request_handshake_retry = FALSE; } - if (!this->batch) + if (this->is_server && state == PB_STATE_SERVER_WORKING && + this->recs->have_recommendation(this->recs, NULL, NULL)) { - if (this->is_server) + check_and_build_recommendation(this); + } + + if (this->batch_type == PB_BATCH_NONE) + { + if (this->is_server && state == PB_STATE_SERVER_WORKING) { - if (state == PB_STATE_SERVER_WORKING) + if (this->state_machine->get_empty_cdata(this->state_machine)) { check_and_build_recommendation(this); } + else + { + DBG2(DBG_TNC, "no recommendation available yet, " + "sending empty PB-TNC SDATA batch"); + this->batch_type = PB_BATCH_SDATA; + } } else - { + { /** - * if the DECIDED state has been reached and no CRETRY is under way - * or if a CLOSE batch with error messages has been received, + * In the DECIDED state and if no CRETRY is under way, * a PB-TNC client replies with an empty CLOSE batch. */ - if (state == PB_STATE_DECIDED || state == PB_STATE_END) + if (state == PB_STATE_DECIDED) { - this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE); + this->batch_type = PB_BATCH_CLOSE; } } } - if (this->batch) + if (this->batch_type != PB_BATCH_NONE) { - pb_tnc_batch_type_t batch_type; + pb_tnc_batch_t *batch; + pb_tnc_msg_t *msg; chunk_t data; + int msg_count; + enumerator_t *enumerator; - batch_type = this->batch->get_type(this->batch); - - if (this->state_machine->send_batch(this->state_machine, batch_type)) + if (this->state_machine->send_batch(this->state_machine, this->batch_type)) { - this->batch->build(this->batch); - data = this->batch->get_encoding(this->batch); + batch = pb_tnc_batch_create(this->is_server, this->batch_type, + min(this->max_batch_len, *buflen)); + + enumerator = this->messages->create_enumerator(this->messages); + while (enumerator->enumerate(enumerator, &msg)) + { + if (batch->add_msg(batch, msg)) + { + this->messages->remove_at(this->messages, enumerator); + } + else + { + break; + } + } + enumerator->destroy(enumerator); + + batch->build(batch); + data = batch->get_encoding(batch); DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u", - pb_tnc_batch_type_names, batch_type, data.len, + pb_tnc_batch_type_names, this->batch_type, data.len, this->connection_id); DBG3(DBG_TNC, "%B", &data); - *msglen = data.len; - if (data.len > *buflen) + *buflen = data.len; + *msglen = 0; + memcpy(buf, data.ptr, *buflen); + batch->destroy(batch); + + msg_count = this->messages->get_count(this->messages); + if (msg_count) { - DBG1(DBG_TNC, "fragmentation of PB-TNC batch not supported yet"); + DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch", + msg_count, (msg_count == 1) ? "" : "s", + pb_tnc_batch_type_names, this->batch_type); } else { - *buflen = data.len; + this->batch_type = PB_BATCH_NONE; } - memcpy(buf, data.ptr, *buflen); + status = ALREADY_DONE; } else { - DBG1(DBG_TNC, "cancelling unexpected PB-TNC batch type: %N", - pb_tnc_batch_type_names, batch_type); + change_batch_type(this, PB_BATCH_NONE); status = INVALID_STATE; } - - this->batch->destroy(this->batch); - this->batch = NULL; } else { @@ -715,7 +783,8 @@ METHOD(tls_t, destroy, void, this->is_server); this->state_machine->destroy(this->state_machine); this->mutex->destroy(this->mutex); - DESTROY_IF(this->batch); + this->messages->destroy_offset(this->messages, + offsetof(pb_tnc_msg_t, destroy)); free(this); } @@ -739,6 +808,13 @@ tls_t *tnccs_20_create(bool is_server) .is_server = is_server, .state_machine = pb_tnc_state_machine_create(is_server), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .messages = linked_list_create(), + .max_batch_len = lib->settings->get_int(lib->settings, + "%s.plugins.tnccs-20.max_batch_size", 65522, + charon->name), + .max_msg_len = lib->settings->get_int(lib->settings, + "%s.plugins.tnccs-20.max_message_size", 65490, + charon->name), ); return &this->public; diff --git a/src/libcharon/plugins/tnccs_dynamic/Makefile.in b/src/libcharon/plugins/tnccs_dynamic/Makefile.in index ab24d32d3..f08d00dab 100644 --- a/src/libcharon/plugins/tnccs_dynamic/Makefile.in +++ b/src/libcharon/plugins/tnccs_dynamic/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -88,7 +89,7 @@ libstrongswan_tnccs_dynamic_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_tnccs_dynamic_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_tnccs_dynamic_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -114,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -208,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -229,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -249,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -258,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/uci/Makefile.in b/src/libcharon/plugins/uci/Makefile.in index dd001e0bd..da9310aa0 100644 --- a/src/libcharon/plugins/uci/Makefile.in +++ b/src/libcharon/plugins/uci/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_uci_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_uci_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_uci_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_uci_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 2f5e59b89..1201f568e 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -169,14 +169,15 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, { DESTROY_IF(this->peer_cfg); ike_cfg = ike_cfg_create(FALSE, FALSE, - local_addr, IKEV2_UDP_PORT, remote_addr, IKEV2_UDP_PORT); + local_addr, FALSE, charon->socket->get_port(charon->socket, FALSE), + remote_addr, FALSE, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); this->peer_cfg = peer_cfg_create( - name, 2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, + name, IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ 1800, 900, /* jitter, overtime */ - TRUE, 60, /* mobike, dpddelay */ - NULL, NULL, /* vip, pool */ + TRUE, FALSE, /* mobike, aggressive */ + 60, 0, /* DPD delay, timeout */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); @@ -264,8 +265,9 @@ METHOD(enumerator_t, ike_enumerator_enumerate, bool, &local_addr, &remote_addr, &ike_proposal)) { DESTROY_IF(this->ike_cfg); - this->ike_cfg = ike_cfg_create(FALSE, FALSE, local_addr, IKEV2_UDP_PORT, - remote_addr, IKEV2_UDP_PORT); + this->ike_cfg = ike_cfg_create(FALSE, FALSE, + local_addr, FALSE, charon->socket->get_port(charon->socket, FALSE), + remote_addr, FALSE, IKEV2_UDP_PORT); this->ike_cfg->add_proposal(this->ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c index af4a6a711..53221b786 100644 --- a/src/libcharon/plugins/uci/uci_control.c +++ b/src/libcharon/plugins/uci/uci_control.c @@ -42,11 +42,6 @@ struct private_uci_control_t { * Public part */ uci_control_t public; - - /** - * Job - */ - callback_job_t *job; }; /** @@ -84,7 +79,7 @@ static void status(private_uci_control_t *this, char *name) FILE *out = NULL; configs = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (configs->enumerate(configs, &peer_cfg)) { if (name && !streq(name, peer_cfg->get_name(peer_cfg))) @@ -269,7 +264,6 @@ static job_requeue_t receive(private_uci_control_t *this) METHOD(uci_control_t, destroy, void, private_uci_control_t *this) { - this->job->cancel(this->job); unlink(FIFO_FILE); free(this); } @@ -295,9 +289,10 @@ uci_control_t *uci_control_create() } else { - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, + this, NULL, (callback_job_cancel_t)return_false, + JOB_PRIO_CRITICAL)); } return &this->public; } diff --git a/src/libcharon/plugins/unit_tester/Makefile.in b/src/libcharon/plugins/unit_tester/Makefile.in index 106c9b1fe..9d936a273 100644 --- a/src/libcharon/plugins/unit_tester/Makefile.in +++ b/src/libcharon/plugins/unit_tester/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -89,7 +90,7 @@ libstrongswan_unit_tester_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_unit_tester_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_unit_tester_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -115,6 +116,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -209,11 +211,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -230,11 +235,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -250,6 +256,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -259,7 +266,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/unit_tester/tests/test_cert.c b/src/libcharon/plugins/unit_tester/tests/test_cert.c index 342194a4c..f4410a688 100644 --- a/src/libcharon/plugins/unit_tester/tests/test_cert.c +++ b/src/libcharon/plugins/unit_tester/tests/test_cert.c @@ -60,7 +60,7 @@ bool test_cert_x509() { return FALSE; } - if (!parsed->issued_by(parsed, ca_cert)) + if (!parsed->issued_by(parsed, ca_cert, NULL)) { return FALSE; } @@ -90,7 +90,7 @@ bool test_cert_x509() { return FALSE; } - if (!parsed->issued_by(parsed, ca_cert)) + if (!parsed->issued_by(parsed, ca_cert, NULL)) { return FALSE; } diff --git a/src/libcharon/plugins/unit_tester/tests/test_pool.c b/src/libcharon/plugins/unit_tester/tests/test_pool.c index a68246fff..f36953f3a 100644 --- a/src/libcharon/plugins/unit_tester/tests/test_pool.c +++ b/src/libcharon/plugins/unit_tester/tests/test_pool.c @@ -27,6 +27,7 @@ static void* testing(void *thread) int i; host_t *addr[ALLOCS]; identification_t *id[ALLOCS]; + linked_list_t *pools; /* prepare identities */ for (i = 0; i < ALLOCS; i++) @@ -37,13 +38,17 @@ static void* testing(void *thread) id[i] = identification_create_from_string(buf); } + pools = linked_list_create(); + pools->insert_last(pools, "test"); + /* allocate addresses */ for (i = 0; i < ALLOCS; i++) { addr[i] = hydra->attributes->acquire_address(hydra->attributes, - "test", id[i], NULL); + pools, id[i], NULL); if (!addr[i]) { + pools->destroy(pools); return (void*)FALSE; } } @@ -52,9 +57,11 @@ static void* testing(void *thread) for (i = 0; i < ALLOCS; i++) { hydra->attributes->release_address(hydra->attributes, - "test", addr[i], id[i]); + pools, addr[i], id[i]); } + pools->destroy(pools); + /* cleanup */ for (i = 0; i < ALLOCS; i++) { diff --git a/src/libcharon/plugins/unity/Makefile.am b/src/libcharon/plugins/unity/Makefile.am new file mode 100644 index 000000000..b23143fd6 --- /dev/null +++ b/src/libcharon/plugins/unity/Makefile.am @@ -0,0 +1,19 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-unity.la +else +plugin_LTLIBRARIES = libstrongswan-unity.la +endif + +libstrongswan_unity_la_SOURCES = \ + unity_plugin.h unity_plugin.c \ + unity_handler.h unity_handler.c \ + unity_narrow.h unity_narrow.c \ + unity_provider.h unity_provider.c + +libstrongswan_unity_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/unity/Makefile.in b/src/libcharon/plugins/unity/Makefile.in new file mode 100644 index 000000000..3b74530b3 --- /dev/null +++ b/src/libcharon/plugins/unity/Makefile.in @@ -0,0 +1,624 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/unity +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_unity_la_LIBADD = +am_libstrongswan_unity_la_OBJECTS = unity_plugin.lo unity_handler.lo \ + unity_narrow.lo unity_provider.lo +libstrongswan_unity_la_OBJECTS = $(am_libstrongswan_unity_la_OBJECTS) +libstrongswan_unity_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_unity_la_LDFLAGS) $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_unity_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_unity_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_unity_la_SOURCES) +DIST_SOURCES = $(libstrongswan_unity_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-unity.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-unity.la +libstrongswan_unity_la_SOURCES = \ + unity_plugin.h unity_plugin.c \ + unity_handler.h unity_handler.c \ + unity_narrow.h unity_narrow.c \ + unity_provider.h unity_provider.c + +libstrongswan_unity_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/unity/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/unity/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-unity.la: $(libstrongswan_unity_la_OBJECTS) $(libstrongswan_unity_la_DEPENDENCIES) + $(libstrongswan_unity_la_LINK) $(am_libstrongswan_unity_la_rpath) $(libstrongswan_unity_la_OBJECTS) $(libstrongswan_unity_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unity_handler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unity_narrow.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unity_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unity_provider.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c new file mode 100644 index 000000000..b2aeba605 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_handler.c @@ -0,0 +1,433 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "unity_handler.h" + +#include +#include +#include +#include + +typedef struct private_unity_handler_t private_unity_handler_t; + +/** + * Private data of an unity_handler_t object. + */ +struct private_unity_handler_t { + + /** + * Public unity_handler_t interface. + */ + unity_handler_t public; + + /** + * List of subnets to include, as entry_t + */ + linked_list_t *include; + + /** + * Mutex for concurrent access to lists + */ + mutex_t *mutex; +}; + +/** + * Traffic selector entry for networks to include under a given IKE_SA + */ +typedef struct { + /** associated IKE_SA, unique ID */ + u_int32_t sa; + /** traffic selector to include/exclude */ + traffic_selector_t *ts; +} entry_t; + +/** + * Clean up an entry + */ +static void entry_destroy(entry_t *this) +{ + this->ts->destroy(this->ts); + free(this); +} + +/** + * Create a traffic selector from a unity subnet definition + */ +static traffic_selector_t *create_ts(chunk_t subnet) +{ + chunk_t net, mask; + int i; + + if (subnet.len != 8) + { + return NULL; + } + net = chunk_create(subnet.ptr, 4); + mask = chunk_clonea(chunk_skip(subnet, 4)); + for (i = 0; i < net.len; i++) + { + mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i]; + } + return traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE, + net, 0, mask, 65535); +} + +/** + * Store a subnet to include in tunnels under this IKE_SA + */ +static bool add_include(private_unity_handler_t *this, chunk_t subnet) +{ + traffic_selector_t *ts; + ike_sa_t *ike_sa; + entry_t *entry; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + ts = create_ts(subnet); + if (!ts) + { + return FALSE; + } + INIT(entry, + .sa = ike_sa->get_unique_id(ike_sa), + .ts = ts, + ); + + this->mutex->lock(this->mutex); + this->include->insert_last(this->include, entry); + this->mutex->unlock(this->mutex); + return TRUE; +} + +/** + * Rempve a subnet from the inclusion list for this IKE_SA + */ +static bool remove_include(private_unity_handler_t *this, chunk_t subnet) +{ + enumerator_t *enumerator; + traffic_selector_t *ts; + ike_sa_t *ike_sa; + entry_t *entry; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + ts = create_ts(subnet); + if (!ts) + { + return FALSE; + } + + this->mutex->lock(this->mutex); + enumerator = this->include->create_enumerator(this->include); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->sa == ike_sa->get_unique_id(ike_sa) && + ts->equals(ts, entry->ts)) + { + this->include->remove_at(this->include, enumerator); + entry_destroy(entry); + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + ts->destroy(ts); + return TRUE; +} + +/** + * Create a unique shunt name for a bypass policy + */ +static void create_shunt_name(ike_sa_t *ike_sa, traffic_selector_t *ts, + char *buf, size_t len) +{ + snprintf(buf, len, "Unity (%s[%u]: %R)", ike_sa->get_name(ike_sa), + ike_sa->get_unique_id(ike_sa), ts); +} + +/** + * Install entry as a shunt policy + */ +static job_requeue_t add_exclude_async(entry_t *entry) +{ + enumerator_t *enumerator; + child_cfg_t *child_cfg; + lifetime_cfg_t lft = {}; + ike_sa_t *ike_sa; + char name[128]; + host_t *host; + bool has_vip = FALSE; + + ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, + entry->sa, FALSE); + if (ike_sa) + { + create_shunt_name(ike_sa, entry->ts, name, sizeof(name)); + + child_cfg = child_cfg_create(name, &lft, NULL, TRUE, MODE_PASS, + ACTION_NONE, ACTION_NONE, ACTION_NONE, + FALSE, 0, 0, NULL, NULL, FALSE); + child_cfg->add_traffic_selector(child_cfg, FALSE, + entry->ts->clone(entry->ts)); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + has_vip = TRUE; + child_cfg->add_traffic_selector(child_cfg, TRUE, + traffic_selector_create_from_subnet(host->clone(host), 32, 0, 0)); + } + enumerator->destroy(enumerator); + + if (!has_vip) + { + host = ike_sa->get_my_host(ike_sa); + child_cfg->add_traffic_selector(child_cfg, TRUE, + traffic_selector_create_from_subnet(host->clone(host), 32, 0, 0)); + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + + charon->shunts->install(charon->shunts, child_cfg); + child_cfg->destroy(child_cfg); + + DBG1(DBG_IKE, "installed %N bypass policy for %R", + configuration_attribute_type_names, UNITY_LOCAL_LAN, entry->ts); + } + return JOB_REQUEUE_NONE; +} + +/** + * Add a bypass policy for a given subnet + */ +static bool add_exclude(private_unity_handler_t *this, chunk_t subnet) +{ + traffic_selector_t *ts; + ike_sa_t *ike_sa; + entry_t *entry; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + ts = create_ts(subnet); + if (!ts) + { + return FALSE; + } + INIT(entry, + .sa = ike_sa->get_unique_id(ike_sa), + .ts = ts, + ); + + /* we can't install the shunt policy yet, as we don't know the virtual IP. + * Defer installation using an async callback. */ + lib->processor->queue_job(lib->processor, (job_t*) + callback_job_create((void*)add_exclude_async, entry, + (void*)entry_destroy, NULL)); + return TRUE; +} + +/** + * Remove a bypass policy for a given subnet + */ +static bool remove_exclude(private_unity_handler_t *this, chunk_t subnet) +{ + traffic_selector_t *ts; + ike_sa_t *ike_sa; + char name[128]; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + ts = create_ts(subnet); + if (!ts) + { + return FALSE; + } + create_shunt_name(ike_sa, ts, name, sizeof(name)); + DBG1(DBG_IKE, "uninstalling %N bypass policy for %R", + configuration_attribute_type_names, UNITY_LOCAL_LAN, ts); + ts->destroy(ts); + return charon->shunts->uninstall(charon->shunts, name); +} + +METHOD(attribute_handler_t, handle, bool, + private_unity_handler_t *this, identification_t *id, + configuration_attribute_type_t type, chunk_t data) +{ + switch (type) + { + case UNITY_SPLIT_INCLUDE: + return add_include(this, data); + case UNITY_LOCAL_LAN: + return add_exclude(this, data); + default: + return FALSE; + } +} + +METHOD(attribute_handler_t, release, void, + private_unity_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + switch (type) + { + case UNITY_SPLIT_INCLUDE: + remove_include(this, data); + break; + case UNITY_LOCAL_LAN: + remove_exclude(this, data); + break; + default: + break; + } +} + +/** + * Configuration attributes to request + */ +static configuration_attribute_type_t attributes[] = { + UNITY_SPLIT_INCLUDE, + UNITY_LOCAL_LAN, +}; + +/** + * Attribute enumerator implementation + */ +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** position in attributes[] */ + int i; +} attribute_enumerator_t; + +METHOD(enumerator_t, enumerate_attributes, bool, + attribute_enumerator_t *this, configuration_attribute_type_t *type, + chunk_t *data) +{ + if (this->i < countof(attributes)) + { + *type = attributes[this->i++]; + *data = chunk_empty; + return TRUE; + } + return FALSE; +} + +METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *, + unity_handler_t *this, identification_t *id, linked_list_t *vips) +{ + attribute_enumerator_t *enumerator; + ike_sa_t *ike_sa; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa || ike_sa->get_version(ike_sa) != IKEV1 || + !ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY)) + { + return enumerator_create_empty(); + } + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_attributes, + .destroy = (void*)free, + }, + ); + return &enumerator->public; +} + +typedef struct { + /** mutex to unlock */ + mutex_t *mutex; + /** IKE_SA ID to filter for */ + u_int32_t id; +} include_filter_t; + +/** + * Include enumerator filter function + */ +static bool include_filter(include_filter_t *data, + entry_t **entry, traffic_selector_t **ts) +{ + if ((*entry)->sa == data->id) + { + *ts = (*entry)->ts; + return TRUE; + } + return FALSE; +} + +/** + * Destroy include filter data, unlock mutex + */ +static void destroy_filter(include_filter_t *data) +{ + data->mutex->unlock(data->mutex); + free(data); +} + +METHOD(unity_handler_t, create_include_enumerator, enumerator_t*, + private_unity_handler_t *this, u_int32_t id) +{ + include_filter_t *data; + + INIT(data, + .mutex = this->mutex, + .id = id, + ); + data->mutex->lock(data->mutex); + return enumerator_create_filter( + this->include->create_enumerator(this->include), + (void*)include_filter, data, (void*)destroy_filter); +} + +METHOD(unity_handler_t, destroy, void, + private_unity_handler_t *this) +{ + this->include->destroy(this->include); + this->mutex->destroy(this->mutex); + free(this); +} + +/** + * See header + */ +unity_handler_t *unity_handler_create() +{ + private_unity_handler_t *this; + + INIT(this, + .public = { + .handler = { + .handle = _handle, + .release = _release, + .create_attribute_enumerator = _create_attribute_enumerator, + }, + .create_include_enumerator = _create_include_enumerator, + .destroy = _destroy, + }, + .include = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/unity/unity_handler.h b/src/libcharon/plugins/unity/unity_handler.h new file mode 100644 index 000000000..8656fd372 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_handler.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup unity_handler unity_handler + * @{ @ingroup unity + */ + +#ifndef UNITY_HANDLER_H_ +#define UNITY_HANDLER_H_ + +#include + +typedef struct unity_handler_t unity_handler_t; + +/** + * Cisco Unity attribute handling. + */ +struct unity_handler_t { + + /** + * Implements attribute_handler_t. + */ + attribute_handler_t handler; + + /** + * Create an enumerator over Split-Include attributes received for an IKE_SA. + * + * @param id IKE_SA unique ID to get Split-Includes for + * @return enumerator over traffic_selector_t* + */ + enumerator_t* (*create_include_enumerator)(unity_handler_t *this, + u_int32_t id); + + /** + * Destroy a unity_handler_t. + */ + void (*destroy)(unity_handler_t *this); +}; + +/** + * Create a unity_handler instance. + */ +unity_handler_t *unity_handler_create(); + +#endif /** UNITY_HANDLER_H_ @}*/ diff --git a/src/libcharon/plugins/unity/unity_narrow.c b/src/libcharon/plugins/unity/unity_narrow.c new file mode 100644 index 000000000..56de0028f --- /dev/null +++ b/src/libcharon/plugins/unity/unity_narrow.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "unity_narrow.h" + +#include + +typedef struct private_unity_narrow_t private_unity_narrow_t; + +/** + * Private data of an unity_narrow_t object. + */ +struct private_unity_narrow_t { + + /** + * Public unity_narrow_t interface. + */ + unity_narrow_t public; + + /** + * Unity attribute handler + */ + unity_handler_t *handler; +}; + +/** + * Narrow TS as initiator to Unity Split-Include/Local-LAN + */ +static void narrow_initiator(private_unity_narrow_t *this, ike_sa_t *ike_sa, + child_cfg_t *cfg, linked_list_t *remote) +{ + traffic_selector_t *current, *orig = NULL; + linked_list_t *received, *selected; + enumerator_t *enumerator; + + enumerator = this->handler->create_include_enumerator(this->handler, + ike_sa->get_unique_id(ike_sa)); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (orig == NULL) + { /* got one, replace original TS */ + if (remote->remove_first(remote, (void**)&orig) != SUCCESS) + { + break; + } + } + /* narrow received Unity TS with the child configuration */ + received = linked_list_create(); + received->insert_last(received, current); + selected = cfg->get_traffic_selectors(cfg, FALSE, received, NULL); + while (selected->remove_first(selected, (void**)¤t) == SUCCESS) + { + remote->insert_last(remote, current); + } + selected->destroy(selected); + received->destroy(received); + } + enumerator->destroy(enumerator); + if (orig) + { + DBG1(DBG_CFG, "narrowed CHILD_SA to %N %#R", + configuration_attribute_type_names, + UNITY_SPLIT_INCLUDE, remote); + orig->destroy(orig); + } +} + +/** + * As initiator, bump up TS to 0.0.0.0/0 for on-the-wire bits + */ +static void narrow_initiator_pre(linked_list_t *list) +{ + traffic_selector_t *ts; + + while (list->remove_first(list, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, + "255.255.255.255", 65535); + if (ts) + { + list->insert_last(list, ts); + } +} + +/** + * As responder, narrow down TS to configuration for installation + */ +static void narrow_responder_post(child_cfg_t *child_cfg, linked_list_t *local) +{ + traffic_selector_t *ts; + linked_list_t *configured; + + while (local->remove_first(local, (void**)&ts) == SUCCESS) + { + ts->destroy(ts); + } + configured = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + + while (configured->remove_first(configured, (void**)&ts) == SUCCESS) + { + local->insert_last(local, ts); + } + configured->destroy(configured); +} + +METHOD(listener_t, narrow, bool, + private_unity_narrow_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, + narrow_hook_t type, linked_list_t *local, linked_list_t *remote) +{ + if (ike_sa->get_version(ike_sa) == IKEV1 && + ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY)) + { + switch (type) + { + case NARROW_INITIATOR_PRE_AUTH: + narrow_initiator_pre(remote); + break; + case NARROW_INITIATOR_POST_AUTH: + narrow_initiator(this, ike_sa, + child_sa->get_config(child_sa), remote); + break; + case NARROW_RESPONDER_POST: + narrow_responder_post(child_sa->get_config(child_sa), local); + break; + default: + break; + } + } + return TRUE; +} + +METHOD(unity_narrow_t, destroy, void, + private_unity_narrow_t *this) +{ + free(this); +} + +/** + * See header + */ +unity_narrow_t *unity_narrow_create(unity_handler_t *handler) +{ + private_unity_narrow_t *this; + + INIT(this, + .public = { + .listener = { + .narrow = _narrow, + }, + .destroy = _destroy, + }, + .handler = handler, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/unity/unity_narrow.h b/src/libcharon/plugins/unity/unity_narrow.h new file mode 100644 index 000000000..5e0968518 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_narrow.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup unity_narrow unity_narrow + * @{ @ingroup unity + */ + +#ifndef UNITY_NARROW_H_ +#define UNITY_NARROW_H_ + +#include + +#include "unity_handler.h" + +typedef struct unity_narrow_t unity_narrow_t; + +/** + * Listener that narrows Quick Modes to the Unity Split-Include subnets. + */ +struct unity_narrow_t { + + /** + * Implements listener_t. + */ + listener_t listener; + + /** + * Destroy a unity_narrow_t. + */ + void (*destroy)(unity_narrow_t *this); +}; + +/** + * Create a unity_narrow instance. + */ +unity_narrow_t *unity_narrow_create(unity_handler_t *handler); + +#endif /** UNITY_NARROW_H_ @}*/ diff --git a/src/libcharon/plugins/unity/unity_plugin.c b/src/libcharon/plugins/unity/unity_plugin.c new file mode 100644 index 000000000..9e21bd9ed --- /dev/null +++ b/src/libcharon/plugins/unity/unity_plugin.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "unity_plugin.h" +#include "unity_handler.h" +#include "unity_narrow.h" +#include "unity_provider.h" + +#include +#include + +typedef struct private_unity_plugin_t private_unity_plugin_t; + +/** + * private data of unity_plugin + */ +struct private_unity_plugin_t { + + /** + * public functions + */ + unity_plugin_t public; + + /** + * Handler for UNITY configuration attributes + */ + unity_handler_t *handler; + + /** + * Responder Unity configuration attribute provider + */ + unity_provider_t *provider; + + /** + * Traffic selector narrower, for Unity Split-Includes + */ + unity_narrow_t *narrower; +}; + +METHOD(plugin_t, get_name, char*, + private_unity_plugin_t *this) +{ + return "unity"; +} + +METHOD(plugin_t, destroy, void, + private_unity_plugin_t *this) +{ + charon->bus->remove_listener(charon->bus, &this->narrower->listener); + this->narrower->destroy(this->narrower); + hydra->attributes->remove_handler(hydra->attributes, &this->handler->handler); + hydra->attributes->remove_provider(hydra->attributes, + &this->provider->provider); + this->handler->destroy(this->handler); + this->provider->destroy(this->provider); + free(this); +} + +/* + * see header file + */ +plugin_t *unity_plugin_create() +{ + private_unity_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .reload = (void*)return_false, + .destroy = _destroy, + }, + }, + .handler = unity_handler_create(), + .provider = unity_provider_create(), + ); + hydra->attributes->add_handler(hydra->attributes, &this->handler->handler); + hydra->attributes->add_provider(hydra->attributes, &this->provider->provider); + + this->narrower = unity_narrow_create(this->handler), + charon->bus->add_listener(charon->bus, &this->narrower->listener); + + return &this->public.plugin; +} diff --git a/src/libcharon/plugins/unity/unity_plugin.h b/src/libcharon/plugins/unity/unity_plugin.h new file mode 100644 index 000000000..0d407b561 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup unity unity + * @ingroup cplugins + * + * @defgroup unity_plugin unity_plugin + * @{ @ingroup unity + */ + +#ifndef UNITY_PLUGIN_H_ +#define UNITY_PLUGIN_H_ + +#include + +typedef struct unity_plugin_t unity_plugin_t; + +/** + * IKEv1 Cisco Unity extension support. + */ +struct unity_plugin_t { + + /** + * Implements plugin_t. interface. + */ + plugin_t plugin; +}; + +#endif /** UNITY_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/unity/unity_provider.c b/src/libcharon/plugins/unity/unity_provider.c new file mode 100644 index 000000000..c7feb090c --- /dev/null +++ b/src/libcharon/plugins/unity/unity_provider.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "unity_provider.h" + +#include + +typedef struct private_unity_provider_t private_unity_provider_t; + +/** + * Private data of an unity_provider_t object. + */ +struct private_unity_provider_t { + + /** + * Public unity_provider_t interface. + */ + unity_provider_t public; +}; + +/** + * Attribute enumerator for traffic selector list + */ +typedef struct { + /** Implements enumerator_t */ + enumerator_t public; + /** list of traffic selectors to enumerate */ + linked_list_t *list; + /** currently enumerating subnet */ + u_char subnet[4]; + /** currently enumerating subnet mask */ + u_char mask[4]; +} attribute_enumerator_t; + +METHOD(enumerator_t, attribute_enumerate, bool, + attribute_enumerator_t *this, configuration_attribute_type_t *type, + chunk_t *attr) +{ + traffic_selector_t *ts; + u_int8_t i, mask; + host_t *net; + + while (TRUE) + { + if (this->list->remove_first(this->list, (void**)&ts) != SUCCESS) + { + return FALSE; + } + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE && + ts->to_subnet(ts, &net, &mask)) + { + ts->destroy(ts); + break; + } + ts->destroy(ts); + } + + memset(this->mask, 0, sizeof(this->mask)); + for (i = 0; i < sizeof(this->mask); i++) + { + if (mask < 8) + { + this->mask[i] = 0xFF << (8 - mask); + break; + } + this->mask[i] = 0xFF; + mask -= 8; + } + memcpy(this->subnet, net->get_address(net).ptr, sizeof(this->subnet)); + net->destroy(net); + + *type = UNITY_SPLIT_INCLUDE; + *attr = chunk_create(this->subnet, sizeof(this->subnet) + sizeof(this->mask)); + + return TRUE; +} + +METHOD(enumerator_t, attribute_destroy, void, + attribute_enumerator_t *this) +{ + this->list->destroy_offset(this->list, offsetof(traffic_selector_t, destroy)); + free(this); +} + +METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, + private_unity_provider_t *this, linked_list_t *pools, identification_t *id, + linked_list_t *vips) +{ + attribute_enumerator_t *attr_enum; + enumerator_t *enumerator; + linked_list_t *list, *current; + traffic_selector_t *ts; + ike_sa_t *ike_sa; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa || ike_sa->get_version(ike_sa) != IKEV1 || + !ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY) || + !vips->get_count(vips)) + { + return NULL; + } + + list = linked_list_create(); + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &child_cfg)) + { + current = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, NULL); + while (current->remove_first(current, (void**)&ts) == SUCCESS) + { + list->insert_last(list, ts); + } + current->destroy(current); + } + enumerator->destroy(enumerator); + + if (list->get_count(list) == 0) + { + list->destroy(list); + return NULL; + } + DBG1(DBG_CFG, "sending %N: %#R", + configuration_attribute_type_names, UNITY_SPLIT_INCLUDE, list); + + INIT(attr_enum, + .public = { + .enumerate = (void*)_attribute_enumerate, + .destroy = _attribute_destroy, + }, + .list = list, + ); + + return &attr_enum->public; +} + +METHOD(unity_provider_t, destroy, void, + private_unity_provider_t *this) +{ + free(this); +} + +/** + * See header + */ +unity_provider_t *unity_provider_create() +{ + private_unity_provider_t *this; + + INIT(this, + .public = { + .provider = { + .acquire_address = (void*)return_null, + .release_address = (void*)return_false, + .create_attribute_enumerator = _create_attribute_enumerator, + }, + .destroy = _destroy, + }, + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/unity/unity_provider.h b/src/libcharon/plugins/unity/unity_provider.h new file mode 100644 index 000000000..a25df5df0 --- /dev/null +++ b/src/libcharon/plugins/unity/unity_provider.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup unity_provider unity_provider + * @{ @ingroup unity + */ + +#ifndef UNITY_PROVIDER_H_ +#define UNITY_PROVIDER_H_ + +typedef struct unity_provider_t unity_provider_t; + +#include + +/** + * Cisco Unity extension attribute provider. + */ +struct unity_provider_t { + + /** + * Implements attribute_provier_t interface. + */ + attribute_provider_t provider; + + /** + * Destroy a unity_provider_t. + */ + void (*destroy)(unity_provider_t *this); +}; + +/** + * Create a unity_provider instance. + */ +unity_provider_t *unity_provider_create(); + +#endif /** UNITY_PROVIDER_H_ @}*/ diff --git a/src/libcharon/plugins/updown/Makefile.am b/src/libcharon/plugins/updown/Makefile.am index 312c8d7e8..30683d83e 100644 --- a/src/libcharon/plugins/updown/Makefile.am +++ b/src/libcharon/plugins/updown/Makefile.am @@ -12,6 +12,7 @@ endif libstrongswan_updown_la_SOURCES = \ updown_plugin.h updown_plugin.c \ + updown_handler.h updown_handler.c \ updown_listener.h updown_listener.c libstrongswan_updown_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/updown/Makefile.in b/src/libcharon/plugins/updown/Makefile.in index fb7b38f65..0f3463704 100644 --- a/src/libcharon/plugins/updown/Makefile.in +++ b/src/libcharon/plugins/updown/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -76,7 +77,7 @@ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_updown_la_LIBADD = am_libstrongswan_updown_la_OBJECTS = updown_plugin.lo \ - updown_listener.lo + updown_handler.lo updown_listener.lo libstrongswan_updown_la_OBJECTS = \ $(am_libstrongswan_updown_la_OBJECTS) libstrongswan_updown_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -85,7 +86,7 @@ libstrongswan_updown_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_updown_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_updown_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -291,6 +297,7 @@ AM_CFLAGS = -rdynamic @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-updown.la libstrongswan_updown_la_SOURCES = \ updown_plugin.h updown_plugin.c \ + updown_handler.h updown_handler.c \ updown_listener.h updown_listener.c libstrongswan_updown_la_LDFLAGS = -module -avoid-version @@ -377,6 +384,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_handler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_listener.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/updown_plugin.Plo@am__quote@ diff --git a/src/libcharon/plugins/updown/updown_handler.c b/src/libcharon/plugins/updown/updown_handler.c new file mode 100644 index 000000000..b2ac02e85 --- /dev/null +++ b/src/libcharon/plugins/updown/updown_handler.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "updown_handler.h" + +#include +#include +#include + +typedef struct private_updown_handler_t private_updown_handler_t; + +/** + * Private data of an updown_handler_t object. + */ +struct private_updown_handler_t { + + /** + * Public updown_handler_t interface. + */ + updown_handler_t public; + + /** + * List of connection specific attributes, as attributes_t + */ + linked_list_t *attrs; + + /** + * rwlock to lock access to pools + */ + rwlock_t *lock; +}; + +/** + * Attributes assigned to an IKE_SA + */ +typedef struct { + /** unique IKE_SA identifier */ + u_int id; + /** list of DNS attributes, as host_t */ + linked_list_t *dns; +} attributes_t; + +/** + * Destroy an attributes_t entry + */ +static void attributes_destroy(attributes_t *this) +{ + this->dns->destroy_offset(this->dns, offsetof(host_t, destroy)); + free(this); +} + +METHOD(attribute_handler_t, handle, bool, + private_updown_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + attributes_t *current, *attr = NULL; + enumerator_t *enumerator; + ike_sa_t *ike_sa; + host_t *host; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + switch (type) + { + case INTERNAL_IP4_DNS: + host = host_create_from_chunk(AF_INET, data, 0); + break; + case INTERNAL_IP6_DNS: + host = host_create_from_chunk(AF_INET6, data, 0); + break; + default: + return FALSE; + } + if (!host) + { + return FALSE; + } + + this->lock->write_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->id == ike_sa->get_unique_id(ike_sa)) + { + attr = current; + } + } + enumerator->destroy(enumerator); + + if (!attr) + { + INIT(attr, + .id = ike_sa->get_unique_id(ike_sa), + .dns = linked_list_create(), + ); + this->attrs->insert_last(this->attrs, attr); + } + attr->dns->insert_last(attr->dns, host); + this->lock->unlock(this->lock); + + return TRUE; +} + +METHOD(attribute_handler_t, release, void, + private_updown_handler_t *this, identification_t *server, + configuration_attribute_type_t type, chunk_t data) +{ + attributes_t *attr; + enumerator_t *enumerator, *servers; + ike_sa_t *ike_sa; + host_t *host; + bool found = FALSE; + int family; + + switch (type) + { + case INTERNAL_IP4_DNS: + family = AF_INET; + break; + case INTERNAL_IP6_DNS: + family = AF_INET6; + break; + default: + return; + } + + ike_sa = charon->bus->get_sa(charon->bus); + if (ike_sa) + { + this->lock->write_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->id == ike_sa->get_unique_id(ike_sa)) + { + servers = attr->dns->create_enumerator(attr->dns); + while (servers->enumerate(servers, &host)) + { + if (host->get_family(host) == family && + chunk_equals(data, host->get_address(host))) + { + attr->dns->remove_at(attr->dns, servers); + host->destroy(host); + found = TRUE; + break; + } + } + servers->destroy(servers); + if (attr->dns->get_count(attr->dns) == 0) + { + this->attrs->remove_at(this->attrs, enumerator); + attributes_destroy(attr); + break; + } + } + if (found) + { + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + } +} + +METHOD(updown_handler_t, create_dns_enumerator, enumerator_t*, + private_updown_handler_t *this, u_int id) +{ + attributes_t *attr; + enumerator_t *enumerator; + ike_sa_t *ike_sa; + + ike_sa = charon->bus->get_sa(charon->bus); + if (!ike_sa) + { + return FALSE; + } + + this->lock->read_lock(this->lock); + enumerator = this->attrs->create_enumerator(this->attrs); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->id == ike_sa->get_unique_id(ike_sa)) + { + enumerator->destroy(enumerator); + return enumerator_create_cleaner( + attr->dns->create_enumerator(attr->dns), + (void*)this->lock->unlock, this->lock); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return enumerator_create_empty(); +} + + +METHOD(updown_handler_t, destroy, void, + private_updown_handler_t *this) +{ + this->lock->destroy(this->lock); + this->attrs->destroy_function(this->attrs, (void*)attributes_destroy); + free(this); +} + +/** + * See header + */ +updown_handler_t *updown_handler_create() +{ + private_updown_handler_t *this; + + INIT(this, + .public = { + .handler = { + .handle = _handle, + .release = _release, + .create_attribute_enumerator = enumerator_create_empty, + }, + .create_dns_enumerator = _create_dns_enumerator, + .destroy = _destroy, + }, + .attrs = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/updown/updown_handler.h b/src/libcharon/plugins/updown/updown_handler.h new file mode 100644 index 000000000..d4de880b8 --- /dev/null +++ b/src/libcharon/plugins/updown/updown_handler.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup updown_handler updown_handler + * @{ @ingroup updown + */ + +#ifndef UPDOWN_HANDLER_H_ +#define UPDOWN_HANDLER_H_ + +#include + +typedef struct updown_handler_t updown_handler_t; + +/** + * Handler storing configuration attributes to pass to updown script. + */ +struct updown_handler_t { + + /** + * Implements the attribute_handler_t interface + */ + attribute_handler_t handler; + + /** + * Create an enumerator over received DNS servers. + * + * @param id unique IKE_SA identifier to get attributes for + * @return enumerator over host_t* + */ + enumerator_t* (*create_dns_enumerator)(updown_handler_t *this, u_int id); + + /** + * Destroy a updown_handler_t. + */ + void (*destroy)(updown_handler_t *this); +}; + +/** + * Create a updown_handler instance. + */ +updown_handler_t *updown_handler_create(); + +#endif /** UPDOWN_HANDLER_H_ @}*/ diff --git a/src/libcharon/plugins/updown/updown_listener.c b/src/libcharon/plugins/updown/updown_listener.c index 2bd757ec7..8b2af05b6 100644 --- a/src/libcharon/plugins/updown/updown_listener.c +++ b/src/libcharon/plugins/updown/updown_listener.c @@ -38,6 +38,11 @@ struct private_updown_listener_t { * List of cached interface names */ linked_list_t *iface_cache; + + /** + * DNS attribute handler + */ + updown_handler_t *handler; }; typedef struct cache_entry_t cache_entry_t; @@ -90,6 +95,85 @@ static char* uncache_iface(private_updown_listener_t *this, u_int32_t reqid) return iface; } +/** + * Create variables for handled DNS attributes + */ +static char *make_dns_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + host_t *host; + int v4 = 0, v6 = 0; + char total[512] = "", current[64]; + + if (!this->handler) + { + return strdup(""); + } + + enumerator = this->handler->create_dns_enumerator(this->handler, + ike_sa->get_unique_id(ike_sa)); + while (enumerator->enumerate(enumerator, &host)) + { + switch (host->get_family(host)) + { + case AF_INET: + snprintf(current, sizeof(current), + "PLUTO_DNS4_%d='%H' ", ++v4, host); + break; + case AF_INET6: + snprintf(current, sizeof(current), + "PLUTO_DNS6_%d='%H' ", ++v6, host); + break; + default: + continue; + } + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + enumerator->destroy(enumerator); + + return strdup(total); +} + +/** + * Create variables for local virtual IPs + */ +static char *make_vip_vars(private_updown_listener_t *this, ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + host_t *host; + int v4 = 0, v6 = 0; + char total[512] = "", current[64]; + bool first = TRUE; + + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + if (first) + { /* legacy variable for first VIP */ + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP='%H' ", host); + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + switch (host->get_family(host)) + { + case AF_INET: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP4_%d='%H' ", ++v4, host); + break; + case AF_INET6: + snprintf(current, sizeof(current), + "PLUTO_MY_SOURCEIP6_%d='%H' ", ++v6, host); + break; + default: + continue; + } + strncat(total, current, sizeof(total) - strlen(total) - 1); + } + enumerator->destroy(enumerator); + + return strdup(total); +} + METHOD(listener_t, child_updown, bool, private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa, bool up) @@ -97,11 +181,10 @@ METHOD(listener_t, child_updown, bool, traffic_selector_t *my_ts, *other_ts; enumerator_t *enumerator; child_cfg_t *config; - host_t *vip, *me, *other; + host_t *me, *other; char *script; config = child_sa->get_config(child_sa); - vip = ike_sa->get_virtual_ip(ike_sa, TRUE); script = config->get_updown(config); me = ike_sa->get_my_host(ike_sa); other = ike_sa->get_other_host(ike_sa); @@ -117,7 +200,7 @@ METHOD(listener_t, child_updown, bool, char command[1024]; host_t *my_client, *other_client; u_int8_t my_client_mask, other_client_mask; - char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc; + char *virtual_ip, *iface, *mark_in, *mark_out, *udp_enc, *dns; mark_t mark; bool is_host, is_ipv6; FILE *shell; @@ -125,20 +208,7 @@ METHOD(listener_t, child_updown, bool, my_ts->to_subnet(my_ts, &my_client, &my_client_mask); other_ts->to_subnet(other_ts, &other_client, &other_client_mask); - if (vip) - { - if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0) - { - virtual_ip = NULL; - } - } - else - { - if (asprintf(&virtual_ip, "") < 0) - { - virtual_ip = NULL; - } - } + virtual_ip = make_vip_vars(this, ike_sa); /* check for the presence of an inbound mark */ mark = config->get_mark(config, TRUE); @@ -197,9 +267,8 @@ METHOD(listener_t, child_updown, bool, if (up) { - iface = hydra->kernel_interface->get_interface( - hydra->kernel_interface, me); - if (iface) + if (hydra->kernel_interface->get_interface(hydra->kernel_interface, + me, &iface)) { cache_iface(this, child_sa->get_reqid(child_sa), iface); } @@ -209,6 +278,8 @@ METHOD(listener_t, child_updown, bool, iface = uncache_iface(this, child_sa->get_reqid(child_sa)); } + dns = make_dns_vars(this, ike_sa); + /* determine IPv4/IPv6 and client/host situation */ is_host = my_ts->is_host(my_ts, me); is_ipv6 = is_host ? (me->get_family(me) == AF_INET6) : @@ -239,6 +310,7 @@ METHOD(listener_t, child_updown, bool, "%s" "%s" "%s" + "%s" "%s", up ? "up" : "down", is_host ? "-host" : "-client", @@ -259,6 +331,7 @@ METHOD(listener_t, child_updown, bool, mark_out, udp_enc, config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "", + dns, script); my_client->destroy(my_client); other_client->destroy(other_client); @@ -266,6 +339,7 @@ METHOD(listener_t, child_updown, bool, free(mark_in); free(mark_out); free(udp_enc); + free(dns); free(iface); DBG3(DBG_CHD, "running updown script: %s", command); @@ -315,7 +389,7 @@ METHOD(updown_listener_t, destroy, void, /** * See header */ -updown_listener_t *updown_listener_create() +updown_listener_t *updown_listener_create(updown_handler_t *handler) { private_updown_listener_t *this; @@ -327,6 +401,7 @@ updown_listener_t *updown_listener_create() .destroy = _destroy, }, .iface_cache = linked_list_create(), + .handler = handler, ); return &this->public; diff --git a/src/libcharon/plugins/updown/updown_listener.h b/src/libcharon/plugins/updown/updown_listener.h index 5b866c4e5..2d9b56ade 100644 --- a/src/libcharon/plugins/updown/updown_listener.h +++ b/src/libcharon/plugins/updown/updown_listener.h @@ -23,6 +23,8 @@ #include +#include "updown_handler.h" + typedef struct updown_listener_t updown_listener_t; /** @@ -44,6 +46,6 @@ struct updown_listener_t { /** * Create a updown_listener instance. */ -updown_listener_t *updown_listener_create(); +updown_listener_t *updown_listener_create(updown_handler_t *handler); #endif /** UPDOWN_LISTENER_H_ @}*/ diff --git a/src/libcharon/plugins/updown/updown_plugin.c b/src/libcharon/plugins/updown/updown_plugin.c index 2ce2d3257..e1f0d1380 100644 --- a/src/libcharon/plugins/updown/updown_plugin.c +++ b/src/libcharon/plugins/updown/updown_plugin.c @@ -15,8 +15,10 @@ #include "updown_plugin.h" #include "updown_listener.h" +#include "updown_handler.h" #include +#include typedef struct private_updown_plugin_t private_updown_plugin_t; @@ -34,6 +36,11 @@ struct private_updown_plugin_t { * Listener interface, listens to CHILD_SA state changes */ updown_listener_t *listener; + + /** + * Attribute handler, to pass DNS servers to updown + */ + updown_handler_t *handler; }; METHOD(plugin_t, get_name, char*, @@ -47,6 +54,12 @@ METHOD(plugin_t, destroy, void, { charon->bus->remove_listener(charon->bus, &this->listener->listener); this->listener->destroy(this->listener); + if (this->handler) + { + hydra->attributes->remove_handler(hydra->attributes, + &this->handler->handler); + this->handler->destroy(this->handler); + } free(this); } @@ -65,9 +78,16 @@ plugin_t *updown_plugin_create() .destroy = _destroy, }, }, - .listener = updown_listener_create(), ); + if (lib->settings->get_bool(lib->settings, + "charon.plugins.updown.dns_handler", FALSE)) + { + this->handler = updown_handler_create(); + hydra->attributes->add_handler(hydra->attributes, + &this->handler->handler); + } + this->listener = updown_listener_create(this->handler); charon->bus->add_listener(charon->bus, &this->listener->listener); return &this->public.plugin; diff --git a/src/libcharon/plugins/whitelist/Makefile.in b/src/libcharon/plugins/whitelist/Makefile.in index 2534f4bec..80f12df47 100644 --- a/src/libcharon/plugins/whitelist/Makefile.in +++ b/src/libcharon/plugins/whitelist/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -92,7 +93,7 @@ PROGRAMS = $(ipsec_PROGRAMS) am_whitelist_OBJECTS = whitelist.$(OBJEXT) whitelist_OBJECTS = $(am_whitelist_OBJECTS) whitelist_LDADD = $(LDADD) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -119,6 +120,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -213,11 +215,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -234,11 +239,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -254,6 +260,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -263,7 +270,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libcharon/plugins/whitelist/whitelist.c b/src/libcharon/plugins/whitelist/whitelist.c index 5f511f2c5..0a3a34459 100644 --- a/src/libcharon/plugins/whitelist/whitelist.c +++ b/src/libcharon/plugins/whitelist/whitelist.c @@ -80,6 +80,7 @@ static int send_msg(int type, char *id) { break; } + msg.id[sizeof(msg.id) - 1] = '\0'; printf("%s\n", msg.id); } } diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c index 202c9a418..a75ea9aee 100644 --- a/src/libcharon/plugins/whitelist/whitelist_control.c +++ b/src/libcharon/plugins/whitelist/whitelist_control.c @@ -49,11 +49,6 @@ struct private_whitelist_control_t { * Whitelist unix socket file descriptor */ int socket; - - /** - * Callback job dispatching commands - */ - callback_job_t *job; }; /** @@ -82,7 +77,8 @@ static bool open_socket(private_whitelist_control_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->uid, charon->gid) != 0) + if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) { DBG1(DBG_CFG, "changing whitelist socket permissions failed: %s", strerror(errno)); @@ -200,7 +196,6 @@ static job_requeue_t receive(private_whitelist_control_t *this) METHOD(whitelist_control_t, destroy, void, private_whitelist_control_t *this) { - this->job->cancel(this->job); close(this->socket); free(this); } @@ -225,9 +220,9 @@ whitelist_control_t *whitelist_control_create(whitelist_listener_t *listener) return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive, this, + NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libcharon/plugins/whitelist/whitelist_listener.c b/src/libcharon/plugins/whitelist/whitelist_listener.c index 5634e3ef8..64ef04800 100644 --- a/src/libcharon/plugins/whitelist/whitelist_listener.c +++ b/src/libcharon/plugins/whitelist/whitelist_listener.c @@ -206,7 +206,7 @@ whitelist_listener_t *whitelist_listener_create() .ids = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 32), .enabled = lib->settings->get_bool(lib->settings, - "charon.plugins.whitelist.enable", FALSE), + "%s.plugins.whitelist.enable", FALSE, charon->name), ); return &this->public; diff --git a/src/libcharon/plugins/xauth_eap/Makefile.am b/src/libcharon/plugins/xauth_eap/Makefile.am new file mode 100644 index 000000000..f2cb0e26c --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-eap.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-eap.la +endif + +libstrongswan_xauth_eap_la_SOURCES = \ + xauth_eap_plugin.h xauth_eap_plugin.c \ + xauth_eap.h xauth_eap.c + +libstrongswan_xauth_eap_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_eap/Makefile.in b/src/libcharon/plugins/xauth_eap/Makefile.in new file mode 100644 index 000000000..709e2be03 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/xauth_eap +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_xauth_eap_la_LIBADD = +am_libstrongswan_xauth_eap_la_OBJECTS = xauth_eap_plugin.lo \ + xauth_eap.lo +libstrongswan_xauth_eap_la_OBJECTS = \ + $(am_libstrongswan_xauth_eap_la_OBJECTS) +libstrongswan_xauth_eap_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_xauth_eap_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_xauth_eap_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_xauth_eap_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_xauth_eap_la_SOURCES) +DIST_SOURCES = $(libstrongswan_xauth_eap_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-eap.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-eap.la +libstrongswan_xauth_eap_la_SOURCES = \ + xauth_eap_plugin.h xauth_eap_plugin.c \ + xauth_eap.h xauth_eap.c + +libstrongswan_xauth_eap_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_eap/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_eap/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-xauth-eap.la: $(libstrongswan_xauth_eap_la_OBJECTS) $(libstrongswan_xauth_eap_la_DEPENDENCIES) + $(libstrongswan_xauth_eap_la_LINK) $(am_libstrongswan_xauth_eap_la_rpath) $(libstrongswan_xauth_eap_la_OBJECTS) $(libstrongswan_xauth_eap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_eap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_eap_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.c b/src/libcharon/plugins/xauth_eap/xauth_eap.c new file mode 100644 index 000000000..1da1d9f85 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_eap.h" + +#include + +#include +#include + +typedef struct private_xauth_eap_t private_xauth_eap_t; + +/** + * Private data of an xauth_eap_t object. + */ +struct private_xauth_eap_t { + + /** + * Public interface. + */ + xauth_eap_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * Callback credential set + */ + callback_cred_t *cred; + + /** + * XAuth password + */ + chunk_t pass; +}; + +/** + * Callback credential set function + */ +static shared_key_t* shared_cb(private_xauth_eap_t *this, shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + shared_key_t *shared; + + if (!this->pass.len) + { + return NULL; + } + if (type != SHARED_EAP && type != SHARED_ANY) + { + return NULL; + } + if (me) + { + if (!this->peer->equals(this->peer, me)) + { + return NULL; + } + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + } + else if (match_me) + { + *match_me = ID_MATCH_ANY; + } + if (other) + { + if (!this->server->equals(this->server, other)) + { + return NULL; + } + if (match_other) + { + *match_other = ID_MATCH_PERFECT; + } + } + else if (match_other) + { + *match_other = ID_MATCH_ANY; + } + shared = shared_key_create(SHARED_EAP, chunk_clone(this->pass)); + this->pass = chunk_empty; + return shared; +} + +/** + * Do EAP exchanges to verify secret + */ +static bool verify_eap(private_xauth_eap_t *this, eap_method_t *backend) +{ + eap_payload_t *request, *response; + eap_method_t *frontend; + eap_type_t type; + u_int32_t vendor; + status_t status; + + if (backend->initiate(backend, &request) != NEED_MORE) + { + return FALSE; + } + type = request->get_type(request, &vendor); + frontend = charon->eap->create_instance(charon->eap, type, vendor, + EAP_PEER, this->server, this->peer); + if (!frontend) + { + DBG1(DBG_IKE, "XAuth-EAP backend requested %N, but not supported", + eap_type_names, type); + request->destroy(request); + return FALSE; + } + while (TRUE) + { + /* credential set is active in frontend only, but not in backend */ + lib->credmgr->add_local_set(lib->credmgr, &this->cred->set, TRUE); + status = frontend->process(frontend, request, &response); + lib->credmgr->remove_local_set(lib->credmgr, &this->cred->set); + request->destroy(request); + if (status != NEED_MORE) + { /* clients should never return SUCCESS */ + frontend->destroy(frontend); + return FALSE; + } + status = backend->process(backend, response, &request); + response->destroy(response); + switch (status) + { + case SUCCESS: + frontend->destroy(frontend); + return TRUE; + case NEED_MORE: + break; + default: + frontend->destroy(frontend); + return FALSE; + } + } +} + +METHOD(xauth_method_t, initiate, status_t, + private_xauth_eap_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, process, status_t, + private_xauth_eap_t *this, cp_payload_t *in, cp_payload_t **out) +{ + configuration_attribute_t *attr; + enumerator_t *enumerator; + identification_t *id; + chunk_t user = chunk_empty; + eap_method_t *backend; + eap_type_t type; + char *name; + bool ok; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + user = attr->get_chunk(attr); + break; + case XAUTH_USER_PASSWORD: + this->pass = attr->get_chunk(attr); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user.ptr || !this->pass.ptr) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + if (user.len) + { + id = identification_create_from_data(user); + if (!id) + { + DBG1(DBG_IKE, "failed to parse provided XAuth username"); + return FAILED; + } + this->peer->destroy(this->peer); + this->peer = id; + } + if (this->pass.len && this->pass.ptr[this->pass.len - 1] == 0) + { /* fix null-terminated passwords (Android etc.) */ + this->pass.len -= 1; + } + + name = lib->settings->get_str(lib->settings, + "%s.plugins.xauth-eap.backend", "radius", + charon->name); + type = eap_type_from_string(name); + if (!type) + { + DBG1(DBG_CFG, "Unknown XAuth-EAP method: %s", name); + return FAILED; + } + backend = charon->eap->create_instance(charon->eap, type, 0, EAP_SERVER, + this->server, this->peer); + if (!backend) + { + DBG1(DBG_CFG, "XAuth-EAP method backend not supported: %s", name); + return FAILED; + } + ok = verify_eap(this, backend); + backend->destroy(backend); + if (ok) + { + return SUCCESS; + } + return FAILED; +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_eap_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_eap_t *this) +{ + this->cred->destroy(this->cred); + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_eap_t *xauth_eap_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_eap_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate, + .process = _process, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + this->cred = callback_cred_create_shared((void*)shared_cb, this); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.h b/src/libcharon/plugins/xauth_eap/xauth_eap.h new file mode 100644 index 000000000..70927247e --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_eap_i xauth_eap + * @{ @ingroup xauth_eap + */ + +#ifndef XAUTH_EAP_H_ +#define XAUTH_EAP_H_ + +typedef struct xauth_eap_t xauth_eap_t; + +#include + +/** + * XAuth method that verifies XAuth credentials using EAP methods. + * + * To reuse existing authentication infrastructure, this XAuth method uses + * EAP to verify XAuth Username/Passwords. It is primarily designed to work + * with the EAP-RADIUS backend and can use any password-based EAP method + * over it. The credentials are fed locally on the IKE responder to a EAP + * client which talks to the backend instance, usually a RADIUS server. + */ +struct xauth_eap_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the XAuth method using EAP, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_eap_t object + */ +xauth_eap_t *xauth_eap_create_server(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_EAP_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c new file mode 100644 index 000000000..b776ec8ea --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_eap_plugin.h" +#include "xauth_eap.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_eap_plugin_t *this) +{ + return "xauth-eap"; +} + +METHOD(plugin_t, get_features, int, + xauth_eap_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_eap_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "eap"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_eap_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_eap_plugin_create() +{ + xauth_eap_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h new file mode 100644 index 000000000..8ba0628b0 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_eap xauth_eap + * @ingroup cplugins + * + * @defgroup xauth_eap_plugin xauth_eap_plugin + * @{ @ingroup xauth_eap + */ + +#ifndef XAUTH_EAP_PLUGIN_H_ +#define XAUTH_EAP_PLUGIN_H_ + +#include + +typedef struct xauth_eap_plugin_t xauth_eap_plugin_t; + +/** + * XAuth plugin using EAP to verify credentials. + */ +struct xauth_eap_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_EAP_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_generic/Makefile.am b/src/libcharon/plugins/xauth_generic/Makefile.am new file mode 100644 index 000000000..0f25e74a2 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-generic.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-generic.la +endif + +libstrongswan_xauth_generic_la_SOURCES = \ + xauth_generic_plugin.h xauth_generic_plugin.c \ + xauth_generic.h xauth_generic.c + +libstrongswan_xauth_generic_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_generic/Makefile.in b/src/libcharon/plugins/xauth_generic/Makefile.in new file mode 100644 index 000000000..9f9743ef1 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/xauth_generic +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_xauth_generic_la_LIBADD = +am_libstrongswan_xauth_generic_la_OBJECTS = xauth_generic_plugin.lo \ + xauth_generic.lo +libstrongswan_xauth_generic_la_OBJECTS = \ + $(am_libstrongswan_xauth_generic_la_OBJECTS) +libstrongswan_xauth_generic_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_xauth_generic_la_LDFLAGS) $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_xauth_generic_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_xauth_generic_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_xauth_generic_la_SOURCES) +DIST_SOURCES = $(libstrongswan_xauth_generic_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-generic.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-generic.la +libstrongswan_xauth_generic_la_SOURCES = \ + xauth_generic_plugin.h xauth_generic_plugin.c \ + xauth_generic.h xauth_generic.c + +libstrongswan_xauth_generic_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_generic/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_generic/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-xauth-generic.la: $(libstrongswan_xauth_generic_la_OBJECTS) $(libstrongswan_xauth_generic_la_DEPENDENCIES) + $(libstrongswan_xauth_generic_la_LINK) $(am_libstrongswan_xauth_generic_la_rpath) $(libstrongswan_xauth_generic_la_OBJECTS) $(libstrongswan_xauth_generic_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_generic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_generic_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c new file mode 100644 index 000000000..f0e675ac0 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_generic.h" + +#include +#include + +typedef struct private_xauth_generic_t private_xauth_generic_t; + +/** + * Private data of an xauth_generic_t object. + */ +struct private_xauth_generic_t { + + /** + * Public interface. + */ + xauth_generic_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + +}; + +METHOD(xauth_method_t, initiate_peer, status_t, + private_xauth_generic_t *this, cp_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +METHOD(xauth_method_t, process_peer, status_t, + private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) +{ + shared_key_t *shared; + cp_payload_t *cp; + chunk_t user, pass; + + shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, this->peer, + this->server); + if (!shared) + { + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", this->peer, + this->server); + return FAILED; + } + + user = this->peer->get_encoding(this->peer); + pass = shared->get_key(shared); + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); + shared->destroy(shared); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, initiate_server, status_t, + private_xauth_generic_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, process_server, status_t, + private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) +{ + configuration_attribute_t *attr; + enumerator_t *enumerator; + shared_key_t *shared; + identification_t *id; + chunk_t user = chunk_empty, pass = chunk_empty; + status_t status = FAILED; + int tried = 0; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + user = attr->get_chunk(attr); + break; + case XAUTH_USER_PASSWORD: + pass = attr->get_chunk(attr); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user.ptr || !pass.ptr) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + if (user.len) + { + id = identification_create_from_data(user); + if (!id) + { + DBG1(DBG_IKE, "failed to parse provided XAuth username"); + return FAILED; + } + this->peer->destroy(this->peer); + this->peer = id; + } + if (pass.len && pass.ptr[pass.len - 1] == 0) + { /* fix null-terminated passwords (Android etc.) */ + pass.len -= 1; + } + + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_EAP, this->server, this->peer); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) + { + if (chunk_equals(shared->get_key(shared), pass)) + { + status = SUCCESS; + break; + } + tried++; + } + enumerator->destroy(enumerator); + if (status != SUCCESS) + { + if (!tried) + { + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", + this->server, this->peer); + } + else + { + DBG1(DBG_IKE, "none of %d found XAuth secrets for '%Y' - '%Y' " + "matched", tried, this->server, this->peer); + } + } + return status; +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_generic_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_generic_t *this) +{ + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_generic_t *xauth_generic_create_peer(identification_t *server, + identification_t *peer) +{ + private_xauth_generic_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_peer, + .process = _process_peer, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + return &this->public; +} + +/* + * Described in header. + */ +xauth_generic_t *xauth_generic_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_generic_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_server, + .process = _process_server, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.h b/src/libcharon/plugins/xauth_generic/xauth_generic.h new file mode 100644 index 000000000..5773589cb --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_generic_i xauth_generic + * @{ @ingroup xauth_generic + */ + +#ifndef XAUTH_GENERIC_H_ +#define XAUTH_GENERIC_H_ + +typedef struct xauth_generic_t xauth_generic_t; + +#include + +/** + * Implementation of the xauth_method_t interface using cleartext secrets + * from any credential set. + */ +struct xauth_generic_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the generic XAuth method, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_generic_t object + */ +xauth_generic_t *xauth_generic_create_server(identification_t *server, + identification_t *peer); + +/** + * Creates the generic XAuth method, acting as peer. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_generic_t object + */ +xauth_generic_t *xauth_generic_create_peer(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_GENERIC_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c new file mode 100644 index 000000000..a87084e20 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_generic_plugin.h" +#include "xauth_generic.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_generic_plugin_t *this) +{ + return "xauth-generic"; +} + +METHOD(plugin_t, get_features, int, + xauth_generic_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_generic_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "generic"), + PLUGIN_CALLBACK(xauth_method_register, xauth_generic_create_peer), + PLUGIN_PROVIDE(XAUTH_PEER, "generic"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_generic_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_generic_plugin_create() +{ + xauth_generic_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h new file mode 100644 index 000000000..426f806a7 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_generic xauth_generic + * @ingroup cplugins + * + * @defgroup xauth_generic_plugin xauth_generic_plugin + * @{ @ingroup xauth_generic + */ + +#ifndef XAUTH_GENERIC_PLUGIN_H_ +#define XAUTH_GENERIC_PLUGIN_H_ + +#include + +typedef struct xauth_generic_plugin_t xauth_generic_plugin_t; + +/** + * XAuth generic plugin using secrets defined in ipsec.secrets. + */ +struct xauth_generic_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_GENERIC_PLUGIN_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_pam/Makefile.am b/src/libcharon/plugins/xauth_pam/Makefile.am new file mode 100644 index 000000000..47521a3ff --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-pam.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-pam.la +endif + +libstrongswan_xauth_pam_la_SOURCES = \ + xauth_pam_plugin.h xauth_pam_plugin.c \ + xauth_pam.h xauth_pam.c + +libstrongswan_xauth_pam_la_LDFLAGS = -module -avoid-version -lpam diff --git a/src/libcharon/plugins/xauth_pam/Makefile.in b/src/libcharon/plugins/xauth_pam/Makefile.in new file mode 100644 index 000000000..c3514473c --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libcharon/plugins/xauth_pam +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_xauth_pam_la_LIBADD = +am_libstrongswan_xauth_pam_la_OBJECTS = xauth_pam_plugin.lo \ + xauth_pam.lo +libstrongswan_xauth_pam_la_OBJECTS = \ + $(am_libstrongswan_xauth_pam_la_OBJECTS) +libstrongswan_xauth_pam_la_LINK = $(LIBTOOL) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libstrongswan_xauth_pam_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_xauth_pam_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_xauth_pam_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_xauth_pam_la_SOURCES) +DIST_SOURCES = $(libstrongswan_xauth_pam_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xauth-pam.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xauth-pam.la +libstrongswan_xauth_pam_la_SOURCES = \ + xauth_pam_plugin.h xauth_pam_plugin.c \ + xauth_pam.h xauth_pam.c + +libstrongswan_xauth_pam_la_LDFLAGS = -module -avoid-version -lpam +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_pam/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libcharon/plugins/xauth_pam/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-xauth-pam.la: $(libstrongswan_xauth_pam_la_OBJECTS) $(libstrongswan_xauth_pam_la_DEPENDENCIES) + $(libstrongswan_xauth_pam_la_LINK) $(am_libstrongswan_xauth_pam_la_rpath) $(libstrongswan_xauth_pam_la_OBJECTS) $(libstrongswan_xauth_pam_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_pam.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_pam_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam.c b/src/libcharon/plugins/xauth_pam/xauth_pam.c new file mode 100644 index 000000000..98c1a97a4 --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_pam.h" + +#include +#include + +#include + +typedef struct private_xauth_pam_t private_xauth_pam_t; + +/** + * Private data of an xauth_pam_t object. + */ +struct private_xauth_pam_t { + + /** + * Public interface. + */ + xauth_pam_t public; + + /** + * ID of the peer + */ + identification_t *peer; +}; + +METHOD(xauth_method_t, initiate, status_t, + private_xauth_pam_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +/** + * PAM conv callback function + */ +static int auth_conv(int num_msg, const struct pam_message **msg, + struct pam_response **resp, char *password) +{ + struct pam_response *response; + + if (num_msg != 1) + { + return PAM_CONV_ERR; + } + response = malloc(sizeof(struct pam_response)); + response->resp = strdup(password); + response->resp_retcode = 0; + *resp = response; + return PAM_SUCCESS; +} + +/** + * Authenticate a username/password using PAM + */ +static bool authenticate(char *service, char *user, char *password) +{ + pam_handle_t *pamh = NULL; + static struct pam_conv conv; + int ret; + + conv.conv = (void*)auth_conv; + conv.appdata_ptr = password; + + ret = pam_start(service, user, &conv, &pamh); + if (ret != PAM_SUCCESS) + { + DBG1(DBG_IKE, "XAuth pam_start for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + return FALSE; + } + ret = pam_authenticate(pamh, 0); + if (ret == PAM_SUCCESS) + { + ret = pam_acct_mgmt(pamh, 0); + if (ret != PAM_SUCCESS) + { + DBG1(DBG_IKE, "XAuth pam_acct_mgmt for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + } + } + else + { + DBG1(DBG_IKE, "XAuth pam_authenticate for '%s' failed: %s", + user, pam_strerror(pamh, ret)); + } + pam_end(pamh, ret); + return ret == PAM_SUCCESS; +} + +/** + * Convert configuration attribute content to a null-terminated string + */ +static void attr2string(char *buf, size_t len, chunk_t chunk) +{ + if (chunk.len && chunk.len < len) + { + snprintf(buf, len, "%.*s", (int)chunk.len, chunk.ptr); + } +} + +METHOD(xauth_method_t, process, status_t, + private_xauth_pam_t *this, cp_payload_t *in, cp_payload_t **out) +{ + char *service, user[128] = "", pass[128] = "", *pos; + configuration_attribute_t *attr; + enumerator_t *enumerator; + chunk_t chunk; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + /* trim to username part if email address given */ + chunk = attr->get_chunk(attr); + pos = memchr(chunk.ptr, '@', chunk.len); + if (pos) + { + chunk.len = (u_char*)pos - chunk.ptr; + } + attr2string(user, sizeof(user), chunk); + break; + case XAUTH_USER_PASSWORD: + attr2string(pass, sizeof(pass), attr->get_chunk(attr)); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user[0] || !pass[0]) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + + this->peer->destroy(this->peer); + this->peer = identification_create_from_string(user); + + /* Look for PAM service, with a legacy fallback for the eap-gtc plugin. + * Default to "login". */ + service = lib->settings->get_str(lib->settings, + "%s.plugins.xauth-pam.pam_service", + lib->settings->get_str(lib->settings, + "%s.plugins.eap-gtc.pam_service", + "login", charon->name), + charon->name); + + if (authenticate(service, user, pass)) + { + DBG1(DBG_IKE, "PAM authentication of '%s' successful", user); + return SUCCESS; + } + return FAILED; +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_pam_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_pam_t *this) +{ + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_pam_t *xauth_pam_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_pam_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate, + .process = _process, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam.h b/src/libcharon/plugins/xauth_pam/xauth_pam.h new file mode 100644 index 000000000..f2d310c0d --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_pam_i xauth_pam + * @{ @ingroup xauth_pam + */ + +#ifndef XAUTH_PAM_H_ +#define XAUTH_PAM_H_ + +typedef struct xauth_pam_t xauth_pam_t; + +#include + +/** + * XAuth plugin using Pluggable Authentication Modules to verify credentials. + */ +struct xauth_pam_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the XAuth method using PAM, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_pam_t object + */ +xauth_pam_t *xauth_pam_create_server(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_PAM_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c new file mode 100644 index 000000000..b9ba0b5ac --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_pam_plugin.h" +#include "xauth_pam.h" + +#include + +#ifndef CAP_AUDIT_WRITE +#define CAP_AUDIT_WRITE 29 +#endif + +METHOD(plugin_t, get_name, char*, + xauth_pam_plugin_t *this) +{ + return "xauth-pam"; +} + +METHOD(plugin_t, get_features, int, + xauth_pam_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_pam_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "pam"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_pam_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_pam_plugin_create() +{ + xauth_pam_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + /* required for PAM authentication */ + charon->caps->keep(charon->caps, CAP_AUDIT_WRITE); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h new file mode 100644 index 000000000..b75268880 --- /dev/null +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_pam xauth_pam + * @ingroup cplugins + * + * @defgroup xauth_pam_plugin xauth_pam_plugin + * @{ @ingroup xauth_pam + */ + +#ifndef XAUTH_PAM_PLUGIN_H_ +#define XAUTH_PAM_PLUGIN_H_ + +#include + +typedef struct xauth_pam_plugin_t xauth_pam_plugin_t; + +/** + * XAuth plugin using Pluggable Authentication Modules to verify credentials. + */ +struct xauth_pam_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_PAM_PLUGIN_H_ @}*/ diff --git a/src/libcharon/processing/jobs/acquire_job.c b/src/libcharon/processing/jobs/acquire_job.c index 2d836b002..207f534ba 100644 --- a/src/libcharon/processing/jobs/acquire_job.c +++ b/src/libcharon/processing/jobs/acquire_job.c @@ -53,12 +53,12 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_acquire_job_t *this) { charon->traps->acquire(charon->traps, this->reqid, this->src_ts, this->dst_ts); - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c new file mode 100644 index 000000000..df5b70c0f --- /dev/null +++ b/src/libcharon/processing/jobs/adopt_children_job.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "adopt_children_job.h" + +#include +#include + +typedef struct private_adopt_children_job_t private_adopt_children_job_t; + +/** + * Private data of an adopt_children_job_t object. + */ +struct private_adopt_children_job_t { + + /** + * Public adopt_children_job_t interface. + */ + adopt_children_job_t public; + + /** + * IKE_SA id to adopt children from + */ + ike_sa_id_t *id; +}; + +METHOD(job_t, destroy, void, + private_adopt_children_job_t *this) +{ + this->id->destroy(this->id); + free(this); +} + +METHOD(job_t, execute, job_requeue_t, + private_adopt_children_job_t *this) +{ + identification_t *my_id, *other_id, *xauth; + host_t *me, *other; + peer_cfg_t *cfg; + linked_list_t *children; + enumerator_t *enumerator, *childenum; + ike_sa_id_t *id; + ike_sa_t *ike_sa; + child_sa_t *child_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id); + if (ike_sa) + { + /* get what we need from new SA */ + me = ike_sa->get_my_host(ike_sa); + me = me->clone(me); + other = ike_sa->get_other_host(ike_sa); + other = other->clone(other); + my_id = ike_sa->get_my_id(ike_sa); + my_id = my_id->clone(my_id); + other_id = ike_sa->get_other_id(ike_sa); + other_id = other_id->clone(other_id); + xauth = ike_sa->get_other_eap_id(ike_sa); + xauth = xauth->clone(xauth); + cfg = ike_sa->get_peer_cfg(ike_sa); + cfg->get_ref(cfg); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + + /* find old SA to adopt children from */ + children = linked_list_create(); + enumerator = charon->ike_sa_manager->create_id_enumerator( + charon->ike_sa_manager, my_id, xauth, + other->get_family(other)); + while (enumerator->enumerate(enumerator, &id)) + { + if (id->equals(id, this->id)) + { /* not from self */ + continue; + } + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); + if (ike_sa) + { + if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED || + ike_sa->get_state(ike_sa) == IKE_PASSIVE) && + me->equals(me, ike_sa->get_my_host(ike_sa)) && + other->equals(other, ike_sa->get_other_host(ike_sa)) && + other_id->equals(other_id, ike_sa->get_other_id(ike_sa)) && + cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa))) + { + childenum = ike_sa->create_child_sa_enumerator(ike_sa); + while (childenum->enumerate(childenum, &child_sa)) + { + ike_sa->remove_child_sa(ike_sa, childenum); + children->insert_last(children, child_sa); + } + childenum->destroy(childenum); + DBG1(DBG_IKE, "detected reauth of existing IKE_SA, " + "adopting %d children", children->get_count(children)); + ike_sa->set_state(ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, ike_sa, FALSE); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, ike_sa); + } + if (children->get_count(children)) + { + break; + } + } + } + enumerator->destroy(enumerator); + + me->destroy(me); + other->destroy(other); + my_id->destroy(my_id); + other_id->destroy(other_id); + xauth->destroy(xauth); + cfg->destroy(cfg); + + if (children->get_count(children)) + { + /* adopt children by new SA */ + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->id); + if (ike_sa) + { + while (children->remove_last(children, + (void**)&child_sa) == SUCCESS) + { + ike_sa->add_child_sa(ike_sa, child_sa); + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } + children->destroy_offset(children, offsetof(child_sa_t, destroy)); + } + return JOB_REQUEUE_NONE; +} + +METHOD(job_t, get_priority, job_priority_t, + private_adopt_children_job_t *this) +{ + return JOB_PRIO_HIGH; +} + +/** + * See header + */ +adopt_children_job_t *adopt_children_job_create(ike_sa_id_t *id) +{ + private_adopt_children_job_t *this; + + INIT(this, + .public = { + .job_interface = { + .execute = _execute, + .get_priority = _get_priority, + .destroy = _destroy, + }, + }, + .id = id->clone(id), + ); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/adopt_children_job.h b/src/libcharon/processing/jobs/adopt_children_job.h new file mode 100644 index 000000000..073504abd --- /dev/null +++ b/src/libcharon/processing/jobs/adopt_children_job.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup adopt_children_job adopt_children_job + * @{ @ingroup cjobs + */ + +#ifndef ADOPT_CHILDREN_JOB_H_ +#define ADOPT_CHILDREN_JOB_H_ + +#include +#include +#include + +typedef struct adopt_children_job_t adopt_children_job_t; + +/** + * Job adopting children after IKEv1 reauthentication from old SA. + */ +struct adopt_children_job_t { + + /** + * Implements job_t. + */ + job_t job_interface; +}; + +/** + * Create a adopt_children_job instance. + * + * @param id ike_sa_id_t of old ISAKMP SA to adopt children from + * @return job + */ +adopt_children_job_t *adopt_children_job_create(ike_sa_id_t *id); + +#endif /** ADOPT_CHILDREN_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c index bd8bb9562..9afbac02b 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.c +++ b/src/libcharon/processing/jobs/delete_child_sa_job.c @@ -44,6 +44,11 @@ struct private_delete_child_sa_job_t { * inbound SPI of the CHILD_SA */ u_int32_t spi; + + /** + * Delete for an expired CHILD_SA + */ + bool expired; }; METHOD(job_t, destroy, void, @@ -52,7 +57,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_delete_child_sa_job_t *this) { ike_sa_t *ike_sa; @@ -66,11 +71,11 @@ METHOD(job_t, execute, void, } else { - ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi); + ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi, this->expired); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, @@ -83,8 +88,7 @@ METHOD(job_t, get_priority, job_priority_t, * Described in header */ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, - protocol_id_t protocol, - u_int32_t spi) + protocol_id_t protocol, u_int32_t spi, bool expired) { private_delete_child_sa_job_t *this; @@ -99,6 +103,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, .reqid = reqid, .protocol = protocol, .spi = spi, + .expired = expired, ); return &this->public; diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h index fc0e2b518..be6d578bc 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.h +++ b/src/libcharon/processing/jobs/delete_child_sa_job.h @@ -50,10 +50,10 @@ struct delete_child_sa_job_t { * @param reqid reqid of the CHILD_SA, as used in kernel * @param protocol protocol of the CHILD_SA * @param spi security parameter index of the CHILD_SA + * @param expired TRUE if CHILD_SA already expired * @return delete_child_sa_job_t object */ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, - protocol_id_t protocol, - u_int32_t spi); + protocol_id_t protocol, u_int32_t spi, bool expired); #endif /** DELETE_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/delete_ike_sa_job.c b/src/libcharon/processing/jobs/delete_ike_sa_job.c index c29b72230..08b41af8c 100644 --- a/src/libcharon/processing/jobs/delete_ike_sa_job.c +++ b/src/libcharon/processing/jobs/delete_ike_sa_job.c @@ -48,7 +48,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_delete_ike_sa_job_t *this) { ike_sa_t *ike_sa; @@ -60,7 +60,7 @@ METHOD(job_t, execute, void, if (ike_sa->get_state(ike_sa) == IKE_PASSIVE) { charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - return destroy(this); + return JOB_REQUEUE_NONE; } if (this->delete_if_established) { @@ -89,7 +89,7 @@ METHOD(job_t, execute, void, } } } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/dpd_timeout_job.c b/src/libcharon/processing/jobs/dpd_timeout_job.c new file mode 100644 index 000000000..91a76bbaf --- /dev/null +++ b/src/libcharon/processing/jobs/dpd_timeout_job.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "dpd_timeout_job.h" + +#include +#include + + +typedef struct private_dpd_timeout_job_t private_dpd_timeout_job_t; + +/** + * Private data + */ +struct private_dpd_timeout_job_t { + + /** + * public dpd_timeout_job_t interface + */ + dpd_timeout_job_t public; + + /** + * IKE_SA identifier + */ + ike_sa_id_t *ike_sa_id; + + /** + * Timestamp of first DPD check + */ + time_t check; +}; + +METHOD(job_t, destroy, void, + private_dpd_timeout_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +METHOD(job_t, execute, job_requeue_t, + private_dpd_timeout_job_t *this) +{ + time_t use_time, current; + enumerator_t *enumerator; + child_sa_t *child_sa; + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + use_time = ike_sa->get_statistic(ike_sa, STAT_INBOUND); + + enumerator = ike_sa->create_child_sa_enumerator(ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + child_sa->get_usestats(child_sa, TRUE, ¤t, NULL); + use_time = max(use_time, current); + } + enumerator->destroy(enumerator); + + /* check if no incoming packet during timeout, reestablish SA */ + if (use_time < this->check) + { + DBG1(DBG_JOB, "DPD check timed out, enforcing DPD action"); + ike_sa->reestablish(ike_sa); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } + return JOB_REQUEUE_NONE; +} + +METHOD(job_t, get_priority, job_priority_t, + private_dpd_timeout_job_t *this) +{ + return JOB_PRIO_HIGH; +} + +/* + * Described in header + */ +dpd_timeout_job_t *dpd_timeout_job_create(ike_sa_id_t *ike_sa_id) +{ + private_dpd_timeout_job_t *this; + + INIT(this, + .public = { + .job_interface = { + .execute = _execute, + .get_priority = _get_priority, + .destroy = _destroy, + }, + }, + .ike_sa_id = ike_sa_id->clone(ike_sa_id), + .check = time_monotonic(NULL), + ); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/dpd_timeout_job.h b/src/libcharon/processing/jobs/dpd_timeout_job.h new file mode 100644 index 000000000..573eb192d --- /dev/null +++ b/src/libcharon/processing/jobs/dpd_timeout_job.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup dpd_timeout_job dpd_timeout_job + * @{ @ingroup cjobs + */ + +#ifndef DPD_TIMEOUT_JOB_H_ +#define DPD_TIMEOUT_JOB_H_ + +typedef struct dpd_timeout_job_t dpd_timeout_job_t; + +#include +#include +#include + +/** + * Job enforcing DPD timeout. + * + * This job detects if a DPD response has been received during the DPD timeout + * interval, and if not, enforced the DPD action. + */ +struct dpd_timeout_job_t { + + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a DPD timeout job. + * + * @param ike_sa_id ike_sa_id_t, gets cloned + * @return initiate_ike_sa_job_t object + */ +dpd_timeout_job_t *dpd_timeout_job_create(ike_sa_id_t *ike_sa_id); + +#endif /** DPD_TIMEOUT_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/inactivity_job.c b/src/libcharon/processing/jobs/inactivity_job.c index 251b9ab03..3c56b0cd7 100644 --- a/src/libcharon/processing/jobs/inactivity_job.c +++ b/src/libcharon/processing/jobs/inactivity_job.c @@ -51,11 +51,11 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_inactivity_job_t *this) { ike_sa_t *ike_sa; - bool rescheduled = FALSE; + u_int32_t reschedule = 0; ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager, this->reqid, TRUE); @@ -87,9 +87,7 @@ METHOD(job_t, execute, void, } else { - lib->scheduler->schedule_job(lib->scheduler, - &this->public.job_interface, this->timeout - diff); - rescheduled = TRUE; + reschedule = this->timeout - diff; } } children++; @@ -108,7 +106,7 @@ METHOD(job_t, execute, void, { DBG1(DBG_JOB, "deleting CHILD_SA after %d seconds " "of inactivity", this->timeout); - status = ike_sa->delete_child_sa(ike_sa, proto, delete); + status = ike_sa->delete_child_sa(ike_sa, proto, delete, FALSE); } } if (status == DESTROY_ME) @@ -121,10 +119,11 @@ METHOD(job_t, execute, void, charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - if (!rescheduled) + if (reschedule) { - destroy(this); + return JOB_RESCHEDULE(reschedule); } + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/initiate_mediation_job.c b/src/libcharon/processing/jobs/initiate_mediation_job.c index e52f3c6df..17ab83053 100644 --- a/src/libcharon/processing/jobs/initiate_mediation_job.c +++ b/src/libcharon/processing/jobs/initiate_mediation_job.c @@ -54,7 +54,7 @@ METHOD(job_t, destroy, void, */ static bool initiate_callback(private_initiate_mediation_job_t *this, debug_t group, level_t level, ike_sa_t *ike_sa, - char *format, va_list args) + char *message) { if (ike_sa && !this->mediation_sa_id) { @@ -64,7 +64,7 @@ static bool initiate_callback(private_initiate_mediation_job_t *this, return TRUE; } -METHOD(job_t, initiate, void, +METHOD(job_t, initiate, job_requeue_t, private_initiate_mediation_job_t *this) { ike_sa_t *mediated_sa, *mediation_sa; @@ -93,8 +93,7 @@ METHOD(job_t, initiate, void, mediated_cfg->destroy(mediated_cfg); mediation_cfg->destroy(mediation_cfg); enumerator->destroy(enumerator); - destroy(this); - return; + return JOB_REQUEUE_NONE; } enumerator->destroy(enumerator); @@ -115,8 +114,7 @@ METHOD(job_t, initiate, void, charon->ike_sa_manager->checkin( charon->ike_sa_manager, mediated_sa); } - destroy(this); - return; + return JOB_REQUEUE_NONE; } /* we need an additional reference because initiate consumes one */ mediation_cfg->get_ref(mediation_cfg); @@ -134,8 +132,7 @@ METHOD(job_t, initiate, void, charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, mediated_sa); } - destroy(this); - return; + return JOB_REQUEUE_NONE; } mediation_cfg->destroy(mediation_cfg); @@ -157,18 +154,17 @@ METHOD(job_t, initiate, void, charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, mediated_sa); } - destroy(this); - return; + return JOB_REQUEUE_NONE; } charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa); } mediated_cfg->destroy(mediated_cfg); } - destroy(this); + return JOB_REQUEUE_NONE; } -METHOD(job_t, reinitiate, void, +METHOD(job_t, reinitiate, job_requeue_t, private_initiate_mediation_job_t *this) { ike_sa_t *mediated_sa, *mediation_sa; @@ -205,8 +201,7 @@ METHOD(job_t, reinitiate, void, charon->ike_sa_manager, mediated_sa); } - destroy(this); - return; + return JOB_REQUEUE_NONE; } charon->ike_sa_manager->checkin(charon->ike_sa_manager, mediation_sa); @@ -214,7 +209,7 @@ METHOD(job_t, reinitiate, void, mediated_cfg->destroy(mediated_cfg); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/mediation_job.c b/src/libcharon/processing/jobs/mediation_job.c index 6f02f2a0a..759aad003 100644 --- a/src/libcharon/processing/jobs/mediation_job.c +++ b/src/libcharon/processing/jobs/mediation_job.c @@ -77,7 +77,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_mediation_job_t *this) { ike_sa_id_t *target_sa_id; @@ -98,8 +98,7 @@ METHOD(job_t, execute, void, DBG1(DBG_JOB, "callback for '%Y' to '%Y' failed", this->source, this->target); charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); - destroy(this); - return; + return JOB_REQUEUE_NONE; } } else @@ -112,8 +111,7 @@ METHOD(job_t, execute, void, this->source, this->target); charon->ike_sa_manager->checkin(charon->ike_sa_manager, target_sa); /* FIXME: notify the initiator */ - destroy(this); - return; + return JOB_REQUEUE_NONE; } } @@ -130,7 +128,7 @@ METHOD(job_t, execute, void, DBG1(DBG_JOB, "mediation between '%Y' and '%Y' failed: " "peer is not online anymore", this->source, this->target); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/migrate_job.c b/src/libcharon/processing/jobs/migrate_job.c index eb10e2e46..2ebfc6714 100644 --- a/src/libcharon/processing/jobs/migrate_job.c +++ b/src/libcharon/processing/jobs/migrate_job.c @@ -67,7 +67,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_migrate_job_t *this) { ike_sa_t *ike_sa = NULL; @@ -79,9 +79,10 @@ METHOD(job_t, execute, void, } if (ike_sa) { - enumerator_t *children; + enumerator_t *children, *enumerator; child_sa_t *child_sa; host_t *host; + linked_list_t *vips; children = ike_sa->create_child_sa_enumerator(ike_sa); while (children->enumerate(children, (void**)&child_sa)) @@ -97,27 +98,35 @@ METHOD(job_t, execute, void, ike_sa->set_kmaddress(ike_sa, this->local, this->remote); host = this->local->clone(this->local); - host->set_port(host, IKEV2_UDP_PORT); + host->set_port(host, charon->socket->get_port(charon->socket, FALSE)); ike_sa->set_my_host(ike_sa, host); host = this->remote->clone(this->remote); host->set_port(host, IKEV2_UDP_PORT); ike_sa->set_other_host(ike_sa, host); - if (child_sa->update(child_sa, this->local, this->remote, - ike_sa->get_virtual_ip(ike_sa, TRUE), + vips = linked_list_create(); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + + if (child_sa->update(child_sa, this->local, this->remote, vips, ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) { ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa), child_sa->get_spi(child_sa, TRUE)); } charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + vips->destroy(vips); } else { DBG1(DBG_JOB, "no CHILD_SA found with reqid {%d}", this->reqid); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/process_message_job.c b/src/libcharon/processing/jobs/process_message_job.c index a4924d001..71a2cb45d 100644 --- a/src/libcharon/processing/jobs/process_message_job.c +++ b/src/libcharon/processing/jobs/process_message_job.c @@ -42,7 +42,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_process_message_job_t *this) { ike_sa_t *ike_sa; @@ -59,8 +59,7 @@ METHOD(job_t, execute, void, this->message->get_source(this->message), this->message->get_destination(this->message)); charon->connect_manager->process_check(charon->connect_manager, this->message); - destroy(this); - return; + return JOB_REQUEUE_NONE; } #endif /* ME */ @@ -81,7 +80,7 @@ METHOD(job_t, execute, void, charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.c b/src/libcharon/processing/jobs/rekey_child_sa_job.c index 5855f1bc9..1bf8dc0cb 100644 --- a/src/libcharon/processing/jobs/rekey_child_sa_job.c +++ b/src/libcharon/processing/jobs/rekey_child_sa_job.c @@ -51,7 +51,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_rekey_child_sa_job_t *this) { ike_sa_t *ike_sa; @@ -68,7 +68,7 @@ METHOD(job_t, execute, void, ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/rekey_ike_sa_job.c b/src/libcharon/processing/jobs/rekey_ike_sa_job.c index 5366195fd..712c7c2c1 100644 --- a/src/libcharon/processing/jobs/rekey_ike_sa_job.c +++ b/src/libcharon/processing/jobs/rekey_ike_sa_job.c @@ -46,7 +46,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_rekey_ike_sa_job_t *this) { ike_sa_t *ike_sa; @@ -78,7 +78,7 @@ METHOD(job_t, execute, void, charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/retransmit_job.c b/src/libcharon/processing/jobs/retransmit_job.c index 050f7005a..48c326804 100644 --- a/src/libcharon/processing/jobs/retransmit_job.c +++ b/src/libcharon/processing/jobs/retransmit_job.c @@ -47,7 +47,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_retransmit_job_t *this) { ike_sa_t *ike_sa; @@ -67,7 +67,7 @@ METHOD(job_t, execute, void, charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/retry_initiate_job.c b/src/libcharon/processing/jobs/retry_initiate_job.c new file mode 100644 index 000000000..1cdc3058a --- /dev/null +++ b/src/libcharon/processing/jobs/retry_initiate_job.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "retry_initiate_job.h" + +#include + +typedef struct private_retry_initiate_job_t private_retry_initiate_job_t; + +/** + * Private data of an retry_initiate_job_t object. + */ +struct private_retry_initiate_job_t { + /** + * Public retry_initiate_job_t interface. + */ + retry_initiate_job_t public; + + /** + * ID of the IKE_SA to re-initiate + */ + ike_sa_id_t *ike_sa_id; +}; + +METHOD(job_t, destroy, void, + private_retry_initiate_job_t *this) +{ + this->ike_sa_id->destroy(this->ike_sa_id); + free(this); +} + +METHOD(job_t, execute, job_requeue_t, + private_retry_initiate_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa == NULL) + { + DBG2(DBG_JOB, "IKE_SA to initiate not found"); + } + else + { + if (ike_sa->retry_initiate(ike_sa) == DESTROY_ME) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, + ike_sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } + return JOB_REQUEUE_NONE; +} + +METHOD(job_t, get_priority, job_priority_t, + private_retry_initiate_job_t *this) +{ + return JOB_PRIO_HIGH; +} + +/* + * Described in header + */ +retry_initiate_job_t *retry_initiate_job_create(ike_sa_id_t *ike_sa_id) +{ + private_retry_initiate_job_t *this; + + INIT(this, + .public = { + .job_interface = { + .execute = _execute, + .get_priority = _get_priority, + .destroy = _destroy, + }, + }, + .ike_sa_id = ike_sa_id->clone(ike_sa_id), + ); + + return &(this->public); +} diff --git a/src/libcharon/processing/jobs/retry_initiate_job.h b/src/libcharon/processing/jobs/retry_initiate_job.h new file mode 100644 index 000000000..29f79f23b --- /dev/null +++ b/src/libcharon/processing/jobs/retry_initiate_job.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup retry_initiate_job retry_initiate_job + * @{ @ingroup cjobs + */ + +#ifndef RETRY_INITIATE_JOB_H_ +#define RETRY_INITIATE_JOB_H_ + +typedef struct retry_initiate_job_t retry_initiate_job_t; + +#include +#include +#include + +/** + * This job retries initiating an IKE_SA in case of e.g. a failed DNS lookup. + */ +struct retry_initiate_job_t { + /** + * The job_t interface. + */ + job_t job_interface; +}; + +/** + * Creates a retry_initiate_job_t object. + * + * @param ike_sa_id ID of the IKE_SA to initiate + * @return retry_initiate_job_t object + */ +retry_initiate_job_t *retry_initiate_job_create(ike_sa_id_t *ike_sa_id); + +#endif /** RETRY_INITIATE_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/roam_job.c b/src/libcharon/processing/jobs/roam_job.c index 951ac5ad3..0af4c6c39 100644 --- a/src/libcharon/processing/jobs/roam_job.c +++ b/src/libcharon/processing/jobs/roam_job.c @@ -44,7 +44,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_roam_job_t *this) { ike_sa_t *ike_sa; @@ -82,8 +82,7 @@ METHOD(job_t, execute, void, id->destroy(id); } list->destroy(list); - - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/send_dpd_job.c b/src/libcharon/processing/jobs/send_dpd_job.c index ab00d013d..d2f38b803 100644 --- a/src/libcharon/processing/jobs/send_dpd_job.c +++ b/src/libcharon/processing/jobs/send_dpd_job.c @@ -45,7 +45,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_send_dpd_job_t *this) { ike_sa_t *ike_sa; @@ -63,7 +63,7 @@ METHOD(job_t, execute, void, charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/send_keepalive_job.c b/src/libcharon/processing/jobs/send_keepalive_job.c index 5e128d478..3e3477679 100644 --- a/src/libcharon/processing/jobs/send_keepalive_job.c +++ b/src/libcharon/processing/jobs/send_keepalive_job.c @@ -45,7 +45,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_send_keepalive_job_t *this) { ike_sa_t *ike_sa; @@ -57,7 +57,7 @@ METHOD(job_t, execute, void, ike_sa->send_keepalive(ike_sa); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c index b65181ef8..bc4aaf6d6 100644 --- a/src/libcharon/processing/jobs/start_action_job.c +++ b/src/libcharon/processing/jobs/start_action_job.c @@ -36,7 +36,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_start_action_job_t *this) { enumerator_t *enumerator, *children; @@ -46,14 +46,9 @@ METHOD(job_t, execute, void, char *name; enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) - { - continue; - } - children = peer_cfg->create_child_cfg_enumerator(peer_cfg); while (children->enumerate(children, &child_cfg)) { @@ -88,7 +83,7 @@ METHOD(job_t, execute, void, children->destroy(children); } enumerator->destroy(enumerator); - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/processing/jobs/update_sa_job.c b/src/libcharon/processing/jobs/update_sa_job.c index c4f6e4782..694318522 100644 --- a/src/libcharon/processing/jobs/update_sa_job.c +++ b/src/libcharon/processing/jobs/update_sa_job.c @@ -50,7 +50,7 @@ METHOD(job_t, destroy, void, free(this); } -METHOD(job_t, execute, void, +METHOD(job_t, execute, job_requeue_t, private_update_sa_job_t *this) { ike_sa_t *ike_sa; @@ -71,7 +71,7 @@ METHOD(job_t, execute, void, } charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } - destroy(this); + return JOB_REQUEUE_NONE; } METHOD(job_t, get_priority, job_priority_t, diff --git a/src/libcharon/sa/authenticator.c b/src/libcharon/sa/authenticator.c new file mode 100644 index 000000000..a32b6ab12 --- /dev/null +++ b/src/libcharon/sa/authenticator.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2006-2009 Martin Willi + * Copyright (C) 2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "authenticator.h" + +#include +#include +#include +#include +#include +#include +#include + + +ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS, + "RSA signature", + "pre-shared key", + "DSS signature"); +ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_GSPM, AUTH_DSS, + "ECDSA-256 signature", + "ECDSA-384 signature", + "ECDSA-521 signature", + "secure password method"); +ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_GSPM, + "XAuthInitPSK", + "XAuthRespPSK", + "XAuthInitRSA", + "XauthRespRSA", + "HybridInitRSA", + "HybridRespRSA", +); +ENUM_END(auth_method_names, AUTH_HYBRID_RESP_RSA); + +#ifdef USE_IKEV2 + +/** + * Described in header. + */ +authenticator_t *authenticator_create_builder(ike_sa_t *ike_sa, auth_cfg_t *cfg, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]) +{ + switch ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS)) + { + case AUTH_CLASS_ANY: + /* defaults to PUBKEY */ + case AUTH_CLASS_PUBKEY: + return (authenticator_t*)pubkey_authenticator_create_builder(ike_sa, + received_nonce, sent_init, reserved); + case AUTH_CLASS_PSK: + return (authenticator_t*)psk_authenticator_create_builder(ike_sa, + received_nonce, sent_init, reserved); + case AUTH_CLASS_EAP: + return (authenticator_t*)eap_authenticator_create_builder(ike_sa, + received_nonce, sent_nonce, + received_init, sent_init, reserved); + default: + return NULL; + } +} + +/** + * Described in header. + */ +authenticator_t *authenticator_create_verifier( + ike_sa_t *ike_sa, message_t *message, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]) +{ + auth_payload_t *auth_payload; + + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (auth_payload == NULL) + { + return (authenticator_t*)eap_authenticator_create_verifier(ike_sa, + received_nonce, sent_nonce, + received_init, sent_init, reserved); + } + switch (auth_payload->get_auth_method(auth_payload)) + { + case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + return (authenticator_t*)pubkey_authenticator_create_verifier(ike_sa, + sent_nonce, received_init, reserved); + case AUTH_PSK: + return (authenticator_t*)psk_authenticator_create_verifier(ike_sa, + sent_nonce, received_init, reserved); + default: + return NULL; + } +} + +#endif /* USE_IKEV2 */ + +#ifdef USE_IKEV1 + +/** + * Described in header. + */ +authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, + auth_method_t auth_method, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) +{ + switch (auth_method) + { + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + return (authenticator_t*)psk_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload, FALSE); + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload, KEY_RSA); + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload, KEY_ECDSA); + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + return (authenticator_t*)hybrid_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload); + default: + return NULL; + } +} + +#endif /* USE_IKEV1 */ diff --git a/src/libcharon/sa/authenticator.h b/src/libcharon/sa/authenticator.h new file mode 100644 index 000000000..914f42d9d --- /dev/null +++ b/src/libcharon/sa/authenticator.h @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup authenticator authenticator + * @{ @ingroup sa + */ + +#ifndef AUTHENTICATOR_H_ +#define AUTHENTICATOR_H_ + +typedef enum auth_method_t auth_method_t; +typedef struct authenticator_t authenticator_t; + +#include +#include +#include + +/** + * Method to use for authentication, as defined in IKEv2. + */ +enum auth_method_t { + + /** + * No authentication used. + */ + AUTH_NONE = 0, + + /** + * Computed as specified in section 2.15 of RFC using + * an RSA private key over a PKCS#1 padded hash. + */ + AUTH_RSA = 1, + + /** + * Computed as specified in section 2.15 of RFC using the + * shared key associated with the identity in the ID payload + * and the negotiated prf function + */ + AUTH_PSK = 2, + + /** + * Computed as specified in section 2.15 of RFC using a + * DSS private key over a SHA-1 hash. + */ + AUTH_DSS = 3, + + /** + * ECDSA with SHA-256 on the P-256 curve as specified in RFC 4754 + */ + AUTH_ECDSA_256 = 9, + + /** + * ECDSA with SHA-384 on the P-384 curve as specified in RFC 4754 + */ + AUTH_ECDSA_384 = 10, + + /** + * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754 + */ + AUTH_ECDSA_521 = 11, + + /** + * Generic Secure Password Authentication Method as specified in RFC 6467 + */ + AUTH_GSPM = 12, + + /** + * IKEv1 initiator XAUTH with PSK, outside of IANA range + */ + AUTH_XAUTH_INIT_PSK = 256, + + /** + * IKEv1 responder XAUTH with PSK, outside of IANA range + */ + AUTH_XAUTH_RESP_PSK, + + /** + * IKEv1 initiator XAUTH with RSA, outside of IANA range + */ + AUTH_XAUTH_INIT_RSA, + + /** + * IKEv1 responder XAUTH with RSA, outside of IANA range + */ + AUTH_XAUTH_RESP_RSA, + + /** + * IKEv1 initiator XAUTH, responder RSA, outside of IANA range + */ + AUTH_HYBRID_INIT_RSA, + + /** + * IKEv1 responder XAUTH, initiator RSA, outside of IANA range + */ + AUTH_HYBRID_RESP_RSA, +}; + +/** + * enum names for auth_method_t. + */ +extern enum_name_t *auth_method_names; + +/** + * Authenticator interface implemented by the various authenticators. + * + * An authenticator implementation handles AUTH and EAP payloads. Received + * messages are passed to the process() method, to send authentication data + * the message is passed to the build() method. + */ +struct authenticator_t { + + /** + * Process an incoming message using the authenticator. + * + * @param message message containing authentication payloads + * @return + * - SUCCESS if authentication successful + * - FAILED if authentication failed + * - NEED_MORE if another exchange required + */ + status_t (*process)(authenticator_t *this, message_t *message); + + /** + * Attach authentication data to an outgoing message. + * + * @param message message to add authentication data to + * @return + * - SUCCESS if authentication successful + * - FAILED if authentication failed + * - NEED_MORE if another exchange required + */ + status_t (*build)(authenticator_t *this, message_t *message); + + /** + * Check if the authenticator is capable of mutual authentication. + * + * Some authenticator authenticate both peers, e.g. EAP. To support + * mutual authentication with only a single authenticator (EAP-only + * authentication), it must be mutual. This method is invoked in ike_auth + * to check if the given authenticator is capable of doing so. + */ + bool (*is_mutual)(authenticator_t *this); + + /** + * Destroy authenticator instance. + */ + void (*destroy) (authenticator_t *this); +}; + +/** + * Create an IKEv2 authenticator to build signatures. + * + * @param ike_sa associated ike_sa + * @param cfg authentication configuration + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of the ID payload + * @return authenticator, NULL if not supported + */ +authenticator_t *authenticator_create_builder( + ike_sa_t *ike_sa, auth_cfg_t *cfg, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]); + +/** + * Create an IKEv2 authenticator to verify signatures. + * + * @param ike_sa associated ike_sa + * @param message message containing authentication data + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of the ID payload + * @return authenticator, NULL if not supported + */ +authenticator_t *authenticator_create_verifier( + ike_sa_t *ike_sa, message_t *message, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]); + +/** + * Create an IKEv1 authenticator to build and verify signatures or hash + * payloads. + * + * @note Due to the fixed ID, these authenticators can only be used in one + * direction at a time. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param auth_method negotiated authentication method to use + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) + * @return authenticator, NULL if not supported + */ +authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, + auth_method_t auth_method, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); + +#endif /** AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c deleted file mode 100644 index 9ffe661cc..000000000 --- a/src/libcharon/sa/authenticators/authenticator.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2006-2009 Martin Willi - * Copyright (C) 2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "authenticator.h" - -#include -#include -#include -#include - - -ENUM_BEGIN(auth_method_names, AUTH_RSA, AUTH_DSS, - "RSA signature", - "pre-shared key", - "DSS signature"); -ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_GSPM, AUTH_DSS, - "ECDSA-256 signature", - "ECDSA-384 signature", - "ECDSA-521 signature", - "secure password method"); -ENUM_END(auth_method_names, AUTH_GSPM); - -/** - * Described in header. - */ -authenticator_t *authenticator_create_builder(ike_sa_t *ike_sa, auth_cfg_t *cfg, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]) -{ - switch ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS)) - { - case AUTH_CLASS_ANY: - /* defaults to PUBKEY */ - case AUTH_CLASS_PUBKEY: - return (authenticator_t*)pubkey_authenticator_create_builder(ike_sa, - received_nonce, sent_init, reserved); - case AUTH_CLASS_PSK: - return (authenticator_t*)psk_authenticator_create_builder(ike_sa, - received_nonce, sent_init, reserved); - case AUTH_CLASS_EAP: - return (authenticator_t*)eap_authenticator_create_builder(ike_sa, - received_nonce, sent_nonce, - received_init, sent_init, reserved); - default: - return NULL; - } -} - -/** - * Described in header. - */ -authenticator_t *authenticator_create_verifier( - ike_sa_t *ike_sa, message_t *message, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]) -{ - auth_payload_t *auth_payload; - - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - if (auth_payload == NULL) - { - return (authenticator_t*)eap_authenticator_create_verifier(ike_sa, - received_nonce, sent_nonce, - received_init, sent_init, reserved); - } - switch (auth_payload->get_auth_method(auth_payload)) - { - case AUTH_RSA: - case AUTH_ECDSA_256: - case AUTH_ECDSA_384: - case AUTH_ECDSA_521: - return (authenticator_t*)pubkey_authenticator_create_verifier(ike_sa, - sent_nonce, received_init, reserved); - case AUTH_PSK: - return (authenticator_t*)psk_authenticator_create_verifier(ike_sa, - sent_nonce, received_init, reserved); - default: - return NULL; - } -} - diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h deleted file mode 100644 index 5042e4a73..000000000 --- a/src/libcharon/sa/authenticators/authenticator.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup authenticator authenticator - * @{ @ingroup authenticators - */ - -#ifndef AUTHENTICATOR_H_ -#define AUTHENTICATOR_H_ - -typedef enum auth_method_t auth_method_t; -typedef struct authenticator_t authenticator_t; - -#include -#include -#include - -/** - * Method to use for authentication, as defined in IKEv2. - */ -enum auth_method_t { - /** - * Computed as specified in section 2.15 of RFC using - * an RSA private key over a PKCS#1 padded hash. - */ - AUTH_RSA = 1, - - /** - * Computed as specified in section 2.15 of RFC using the - * shared key associated with the identity in the ID payload - * and the negotiated prf function - */ - AUTH_PSK = 2, - - /** - * Computed as specified in section 2.15 of RFC using a - * DSS private key over a SHA-1 hash. - */ - AUTH_DSS = 3, - - /** - * ECDSA with SHA-256 on the P-256 curve as specified in RFC 4754 - */ - AUTH_ECDSA_256 = 9, - - /** - * ECDSA with SHA-384 on the P-384 curve as specified in RFC 4754 - */ - AUTH_ECDSA_384 = 10, - - /** - * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754 - */ - AUTH_ECDSA_521 = 11, - - /** - * Generic Secure Password Authentication Method as specified in RFC 6467 - */ - AUTH_GSPM = 12, - -}; - -/** - * enum names for auth_method_t. - */ -extern enum_name_t *auth_method_names; - -/** - * Authenticator interface implemented by the various authenticators. - * - * An authenticator implementation handles AUTH and EAP payloads. Received - * messages are passed to the process() method, to send authentication data - * the message is passed to the build() method. - */ -struct authenticator_t { - - /** - * Process an incoming message using the authenticator. - * - * @param message message containing authentication payloads - * @return - * - SUCCESS if authentication successful - * - FAILED if authentication failed - * - NEED_MORE if another exchange required - */ - status_t (*process)(authenticator_t *this, message_t *message); - - /** - * Attach authentication data to an outgoing message. - * - * @param message message to add authentication data to - * @return - * - SUCCESS if authentication successful - * - FAILED if authentication failed - * - NEED_MORE if another exchange required - */ - status_t (*build)(authenticator_t *this, message_t *message); - - /** - * Check if the authenticator is capable of mutual authentication. - * - * Some authenticator authenticate both peers, e.g. EAP. To support - * mutual authentication with only a single authenticator (EAP-only - * authentication), it must be mutual. This method is invoked in ike_auth - * to check if the given authenticator is capable of doing so. - */ - bool (*is_mutual)(authenticator_t *this); - - /** - * Destroy authenticator instance. - */ - void (*destroy) (authenticator_t *this); -}; - -/** - * Create an authenticator to build signatures. - * - * @param ike_sa associated ike_sa - * @param cfg authentication configuration - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of the ID payload - * @return authenticator, NULL if not supported - */ -authenticator_t *authenticator_create_builder( - ike_sa_t *ike_sa, auth_cfg_t *cfg, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]); - -/** - * Create an authenticator to verify signatures. - * - * @param ike_sa associated ike_sa - * @param message message containing authentication data - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of the ID payload - * @return authenticator, NULL if not supported - */ -authenticator_t *authenticator_create_verifier( - ike_sa_t *ike_sa, message_t *message, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]); - -#endif /** AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/eap_manager.c b/src/libcharon/sa/authenticators/eap/eap_manager.c deleted file mode 100644 index bc2c4a617..000000000 --- a/src/libcharon/sa/authenticators/eap/eap_manager.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "eap_manager.h" - -#include -#include - -typedef struct private_eap_manager_t private_eap_manager_t; -typedef struct eap_entry_t eap_entry_t; - -/** - * EAP constructor entry - */ -struct eap_entry_t { - - /** - * EAP method type, vendor specific if vendor is set - */ - eap_type_t type; - - /** - * vendor ID, 0 for default EAP methods - */ - u_int32_t vendor; - - /** - * Role of the method returned by the constructor, EAP_SERVER or EAP_PEER - */ - eap_role_t role; - - /** - * constructor function to create instance - */ - eap_constructor_t constructor; -}; - -/** - * private data of eap_manager - */ -struct private_eap_manager_t { - - /** - * public functions - */ - eap_manager_t public; - - /** - * list of eap_entry_t's - */ - linked_list_t *methods; - - /** - * rwlock to lock methods - */ - rwlock_t *lock; -}; - -METHOD(eap_manager_t, add_method, void, - private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, - eap_role_t role, eap_constructor_t constructor) -{ - eap_entry_t *entry = malloc_thing(eap_entry_t); - - entry->type = type; - entry->vendor = vendor; - entry->role = role; - entry->constructor = constructor; - - this->lock->write_lock(this->lock); - this->methods->insert_last(this->methods, entry); - this->lock->unlock(this->lock); -} - -METHOD(eap_manager_t, remove_method, void, - private_eap_manager_t *this, eap_constructor_t constructor) -{ - enumerator_t *enumerator; - eap_entry_t *entry; - - this->lock->write_lock(this->lock); - enumerator = this->methods->create_enumerator(this->methods); - while (enumerator->enumerate(enumerator, &entry)) - { - if (constructor == entry->constructor) - { - this->methods->remove_at(this->methods, enumerator); - free(entry); - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); -} - -METHOD(eap_manager_t, create_instance, eap_method_t*, - private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, - eap_role_t role, identification_t *server, identification_t *peer) -{ - enumerator_t *enumerator; - eap_entry_t *entry; - eap_method_t *method = NULL; - - this->lock->read_lock(this->lock); - enumerator = this->methods->create_enumerator(this->methods); - while (enumerator->enumerate(enumerator, &entry)) - { - if (type == entry->type && vendor == entry->vendor && - role == entry->role) - { - method = entry->constructor(server, peer); - if (method) - { - break; - } - } - } - enumerator->destroy(enumerator); - this->lock->unlock(this->lock); - return method; -} - -METHOD(eap_manager_t, destroy, void, - private_eap_manager_t *this) -{ - this->methods->destroy_function(this->methods, free); - this->lock->destroy(this->lock); - free(this); -} - -/* - * See header - */ -eap_manager_t *eap_manager_create() -{ - private_eap_manager_t *this; - - INIT(this, - .public = { - .add_method = _add_method, - .remove_method = _remove_method, - .create_instance = _create_instance, - .destroy = _destroy, - }, - .methods = linked_list_create(), - .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), - ); - - return &this->public; -} - diff --git a/src/libcharon/sa/authenticators/eap/eap_manager.h b/src/libcharon/sa/authenticators/eap/eap_manager.h deleted file mode 100644 index 0333fb6da..000000000 --- a/src/libcharon/sa/authenticators/eap/eap_manager.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup eap_manager eap_manager - * @{ @ingroup eap - */ - -#ifndef EAP_MANAGER_H_ -#define EAP_MANAGER_H_ - -#include - -typedef struct eap_manager_t eap_manager_t; - -/** - * The EAP manager manages all EAP implementations and creates instances. - * - * A plugin registers it's implemented EAP method at the manager by - * providing type and a contructor function. The manager then instanciates - * eap_method_t instances through the provided constructor to handle - * EAP authentication. - */ -struct eap_manager_t { - - /** - * Register a EAP method implementation. - * - * @param method vendor specific method, if vendor != 0 - * @param vendor vendor ID, 0 for non-vendor (default) EAP methods - * @param role EAP role of the registered method - * @param constructor constructor function, returns an eap_method_t - */ - void (*add_method)(eap_manager_t *this, eap_type_t type, u_int32_t vendor, - eap_role_t role, eap_constructor_t constructor); - - /** - * Unregister a EAP method implementation using it's constructor. - * - * @param constructor constructor function to remove, as added in add_method - */ - void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor); - - /** - * Create a new EAP method instance. - * - * @param type type of the EAP method - * @param vendor vendor ID, 0 for non-vendor (default) EAP methods - * @param role role of EAP method, either EAP_SERVER or EAP_PEER - * @param server identity of the server - * @param peer identity of the peer (client) - * @return EAP method instance, NULL if no constructor found - */ - eap_method_t* (*create_instance)(eap_manager_t *this, eap_type_t type, - u_int32_t vendor, eap_role_t role, - identification_t *server, - identification_t *peer); - - /** - * Destroy a eap_manager instance. - */ - void (*destroy)(eap_manager_t *this); -}; - -/** - * Create a eap_manager instance. - */ -eap_manager_t *eap_manager_create(); - -#endif /** EAP_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap/eap_method.c b/src/libcharon/sa/authenticators/eap/eap_method.c deleted file mode 100644 index a05e8c59a..000000000 --- a/src/libcharon/sa/authenticators/eap/eap_method.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "eap_method.h" - -#include - -ENUM(eap_role_names, EAP_SERVER, EAP_PEER, - "EAP_SERVER", - "EAP_PEER", -); - -/** - * See header - */ -bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, - bool reg, void *data) -{ - if (reg) - { - charon->eap->add_method(charon->eap, feature->arg.eap, 0, - feature->type == FEATURE_EAP_SERVER ? EAP_SERVER : EAP_PEER, - (eap_constructor_t)data); - } - else - { - charon->eap->remove_method(charon->eap, (eap_constructor_t)data); - } - return TRUE; -} diff --git a/src/libcharon/sa/authenticators/eap/eap_method.h b/src/libcharon/sa/authenticators/eap/eap_method.h deleted file mode 100644 index 6242a5a6e..000000000 --- a/src/libcharon/sa/authenticators/eap/eap_method.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup eap_method eap_method - * @{ @ingroup eap - */ - -#ifndef EAP_METHOD_H_ -#define EAP_METHOD_H_ - -typedef struct eap_method_t eap_method_t; -typedef enum eap_role_t eap_role_t; - -#include -#include -#include -#include -#include - -/** - * Role of an eap_method, SERVER or PEER (client) - */ -enum eap_role_t { - EAP_SERVER, - EAP_PEER, -}; -/** - * enum names for eap_role_t. - */ -extern enum_name_t *eap_role_names; - -/** - * Interface of an EAP method for server and client side. - * - * An EAP method initiates an EAP exchange and processes requests and - * responses. An EAP method may need multiple exchanges before succeeding, and - * the eap_authentication may use multiple EAP methods to authenticate a peer. - * To accomplish these requirements, all EAP methods have their own - * implementation while the eap_authenticatior uses one or more of these - * EAP methods. Sending of EAP(SUCCESS/FAILURE) message is not the job - * of the method, the eap_authenticator does this. - * An EAP method may establish a MSK, this is used the complete the - * authentication. Even if a mutual EAP method is used, the traditional - * AUTH payloads are required. Only these include the nonces and messages from - * ike_sa_init and therefore prevent man in the middle attacks. - * The EAP method must use an initial EAP identifier value != 0, as a preceding - * EAP-Identity exchange always uses identifier 0. - */ -struct eap_method_t { - - /** - * Initiate the EAP exchange. - * - * initiate() is only useable for server implementations, as clients only - * reply to server requests. - * A eap_payload is created in "out" if result is NEED_MORE. - * - * @param out eap_payload to send to the client - * @return - * - NEED_MORE, if an other exchange is required - * - FAILED, if unable to create eap request payload - */ - status_t (*initiate) (eap_method_t *this, eap_payload_t **out); - - /** - * Process a received EAP message. - * - * A eap_payload is created in "out" if result is NEED_MORE. - * - * @param in eap_payload response received - * @param out created eap_payload to send - * @return - * - NEED_MORE, if an other exchange is required - * - FAILED, if EAP method failed - * - SUCCESS, if EAP method succeeded - */ - status_t (*process) (eap_method_t *this, eap_payload_t *in, - eap_payload_t **out); - - /** - * Get the EAP type implemented in this method. - * - * @param vendor pointer receiving vendor identifier for type, 0 for none - * @return type of the EAP method - */ - eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor); - - /** - * Check if this EAP method authenticates the server. - * - * Some EAP methods provide mutual authentication and - * allow authentication using only EAP, if the peer supports it. - * - * @return TRUE if methods provides mutual authentication - */ - bool (*is_mutual) (eap_method_t *this); - - /** - * Get the MSK established by this EAP method. - * - * Not all EAP methods establish a shared secret. For implementations of - * the EAP-Identity method, get_msk() returns the received identity. - * - * @param msk chunk receiving internal stored MSK - * @return - * - SUCCESS, or - * - FAILED, if MSK not established (yet) - */ - status_t (*get_msk) (eap_method_t *this, chunk_t *msk); - - /** - * Get the current EAP identifier. - * - * @return current EAP identifier - */ - u_int8_t (*get_identifier) (eap_method_t *this); - - /** - * Set the EAP identifier to a deterministic value, overwriting - * the randomly initialized default value. - * - * @param identifier current EAP identifier - */ - void (*set_identifier) (eap_method_t *this, u_int8_t identifier); - - /** - * Destroys a eap_method_t object. - */ - void (*destroy) (eap_method_t *this); -}; - -/** - * Constructor definition for a pluggable EAP method. - * - * Each EAP module must define a constructor function which will return - * an initialized object with the methods defined in eap_method_t. - * Constructors for server and peers are identical, to support both roles - * of a EAP method, a plugin needs register two constructors in the - * eap_manager_t. - * The passed identites are of type ID_EAP and valid only during the - * constructor invocation. - * - * @param server ID of the server to use for credential lookup - * @param peer ID of the peer to use for credential lookup - * @return implementation of the eap_method_t interface - */ -typedef eap_method_t *(*eap_constructor_t)(identification_t *server, - identification_t *peer); - -/** - * Helper function to (un-)register EAP methods from plugin features. - * - * This function is a plugin_feature_callback_t and can be used with the - * PLUGIN_CALLBACK macro to register a EAP method constructor. - * - * @param plugin plugin registering the EAP method constructor - * @param feature associated plugin feature - * @param reg TRUE to register, FALSE to unregister. - * @param data data passed to callback, an eap_constructor_t - */ -bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, - bool reg, void *data); - -#endif /** EAP_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c deleted file mode 100644 index 5c8f0b6ce..000000000 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "eap_authenticator.h" - -#include -#include -#include -#include - -typedef struct private_eap_authenticator_t private_eap_authenticator_t; - -/** - * Private data of an eap_authenticator_t object. - */ -struct private_eap_authenticator_t { - - /** - * Public authenticator_t interface. - */ - eap_authenticator_t public; - - /** - * Assigned IKE_SA - */ - ike_sa_t *ike_sa; - - /** - * others nonce to include in AUTH calculation - */ - chunk_t received_nonce; - - /** - * our nonce to include in AUTH calculation - */ - chunk_t sent_nonce; - - /** - * others IKE_SA_INIT message data to include in AUTH calculation - */ - chunk_t received_init; - - /** - * our IKE_SA_INIT message data to include in AUTH calculation - */ - chunk_t sent_init; - - /** - * Reserved bytes of ID payload - */ - char reserved[3]; - - /** - * Current EAP method processing - */ - eap_method_t *method; - - /** - * MSK used to build and verify auth payload - */ - chunk_t msk; - - /** - * EAP authentication method completed successfully - */ - bool eap_complete; - - /** - * Set if we require mutual EAP due EAP-only authentication - */ - bool require_mutual; - - /** - * authentication payload verified successfully - */ - bool auth_complete; - - /** - * generated EAP payload - */ - eap_payload_t *eap_payload; - - /** - * EAP identity of peer - */ - identification_t *eap_identity; -}; - -/** - * load an EAP method - */ -static eap_method_t *load_method(private_eap_authenticator_t *this, - eap_type_t type, u_int32_t vendor, eap_role_t role) -{ - identification_t *server, *peer, *aaa; - auth_cfg_t *auth; - - if (role == EAP_SERVER) - { - server = this->ike_sa->get_my_id(this->ike_sa); - peer = this->ike_sa->get_other_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - } - else - { - server = this->ike_sa->get_other_id(this->ike_sa); - peer = this->ike_sa->get_my_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - } - if (this->eap_identity) - { - peer = this->eap_identity; - } - aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); - if (aaa) - { - server = aaa; - } - return charon->eap->create_instance(charon->eap, type, vendor, - role, server, peer); -} - -/** - * Initiate EAP conversation as server - */ -static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, - bool do_identity) -{ - auth_cfg_t *auth; - eap_type_t type; - identification_t *id; - u_int32_t vendor; - eap_payload_t *out; - char *action; - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - - /* initiate EAP-Identity exchange if required */ - if (!this->eap_identity && do_identity) - { - id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); - if (id) - { - if (id->get_type(id) == ID_ANY) - { - this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER); - if (this->method) - { - if (this->method->initiate(this->method, &out) == NEED_MORE) - { - DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", - eap_type_names, EAP_IDENTITY, - this->method->get_identifier(this->method)); - return out; - } - this->method->destroy(this->method); - } - DBG1(DBG_IKE, "EAP-Identity request configured, " - "but not supported"); - } - else - { - DBG1(DBG_IKE, "using configured EAP-Identity %Y", id); - this->eap_identity = id->clone(id); - } - } - } - /* invoke real EAP method */ - type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); - vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); - action = "loading"; - this->method = load_method(this, type, vendor, EAP_SERVER); - if (this->method) - { - action = "initiating"; - type = this->method->get_type(this->method, &vendor); - if (this->method->initiate(this->method, &out) == NEED_MORE) - { - if (vendor) - { - DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)", - type, vendor, out->get_identifier(out)); - } - else - { - DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names, - type, out->get_identifier(out)); - } - return out; - } - } - if (vendor) - { - DBG1(DBG_IKE, "%s EAP vendor type %d-%d method failed", - action, type, vendor); - } - else - { - DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type); - } - return eap_payload_create_code(EAP_FAILURE, 0); -} - -/** - * Replace the existing EAP-Identity in other auth config - */ -static void replace_eap_identity(private_eap_authenticator_t *this) -{ - identification_t *eap_identity; - auth_cfg_t *cfg; - - eap_identity = this->eap_identity->clone(this->eap_identity); - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity); -} - -/** - * Handle EAP exchange as server - */ -static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, - eap_payload_t *in) -{ - eap_type_t type, received_type; - u_int32_t vendor, received_vendor; - eap_payload_t *out; - - if (in->get_code(in) != EAP_RESPONSE) - { - DBG1(DBG_IKE, "received %N, sending %N", - eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE); - return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); - } - - type = this->method->get_type(this->method, &vendor); - received_type = in->get_type(in, &received_vendor); - if (type != received_type || vendor != received_vendor) - { - if (received_vendor == 0 && received_type == EAP_NAK) - { - DBG1(DBG_IKE, "received %N, sending %N", - eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); - } - else - { - DBG1(DBG_IKE, "received invalid EAP response, sending %N", - eap_code_names, EAP_FAILURE); - } - return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); - } - - switch (this->method->process(this->method, in, &out)) - { - case NEED_MORE: - return out; - case SUCCESS: - if (!vendor && type == EAP_IDENTITY) - { - chunk_t data; - - if (this->method->get_msk(this->method, &data) == SUCCESS) - { - this->eap_identity = identification_create_from_data(data); - DBG1(DBG_IKE, "received EAP identity '%Y'", - this->eap_identity); - replace_eap_identity(this); - } - /* restart EAP exchange, but with real method */ - this->method->destroy(this->method); - return server_initiate_eap(this, FALSE); - } - if (this->method->get_msk(this->method, &this->msk) == SUCCESS) - { - this->msk = chunk_clone(this->msk); - } - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " - "%sMSK established", type, vendor, - this->msk.ptr ? "" : "no "); - } - else - { - DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", - eap_type_names, type, this->msk.ptr ? "" : "no "); - } - this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, - TRUE); - this->eap_complete = TRUE; - return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); - case FAILED: - default: - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " - "peer %Y", type, vendor, - this->ike_sa->get_other_id(this->ike_sa)); - } - else - { - DBG1(DBG_IKE, "EAP method %N failed for peer %Y", - eap_type_names, type, - this->ike_sa->get_other_id(this->ike_sa)); - } - return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); - } -} - -/** - * Processing method for a peer - */ -static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, - eap_payload_t *in) -{ - eap_type_t type; - u_int32_t vendor; - auth_cfg_t *auth; - eap_payload_t *out; - identification_t *id; - - type = in->get_type(in, &vendor); - - if (!vendor && type == EAP_IDENTITY) - { - DESTROY_IF(this->eap_identity); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); - if (!id || id->get_type(id) == ID_ANY) - { - id = this->ike_sa->get_my_id(this->ike_sa); - } - DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'", - eap_type_names, type, in->get_identifier(in), id); - this->eap_identity = id->clone(id); - - this->method = load_method(this, type, vendor, EAP_PEER); - if (this->method) - { - if (this->method->process(this->method, in, &out) == SUCCESS) - { - this->method->destroy(this->method); - this->method = NULL; - return out; - } - this->method->destroy(this->method); - this->method = NULL; - } - DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", - eap_type_names, type); - return eap_payload_create_nak(in->get_identifier(in)); - } - if (this->method == NULL) - { - if (vendor) - { - DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ", - "(id 0x%02X)", type, vendor, in->get_identifier(in)); - } - else - { - DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", - eap_type_names, type, in->get_identifier(in)); - } - this->method = load_method(this, type, vendor, EAP_PEER); - if (!this->method) - { - DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); - return eap_payload_create_nak(in->get_identifier(in)); - } - } - - type = this->method->get_type(this->method, &vendor); - - if (this->method->process(this->method, in, &out) == NEED_MORE) - { /* client methods should never return SUCCESS */ - return out; - } - - if (vendor) - { - DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor); - } - else - { - DBG1(DBG_IKE, "%N method failed", eap_type_names, type); - } - return NULL; -} - -/** - * Verify AUTH payload - */ -static bool verify_auth(private_eap_authenticator_t *this, message_t *message, - chunk_t nonce, chunk_t init) -{ - auth_payload_t *auth_payload; - chunk_t auth_data, recv_auth_data; - identification_t *other_id; - auth_cfg_t *auth; - keymat_t *keymat; - - auth_payload = (auth_payload_t*)message->get_payload(message, - AUTHENTICATION); - if (!auth_payload) - { - DBG1(DBG_IKE, "AUTH payload missing"); - return FALSE; - } - other_id = this->ike_sa->get_other_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); - auth_data = keymat->get_psk_sig(keymat, TRUE, init, nonce, - this->msk, other_id, this->reserved); - recv_auth_data = auth_payload->get_data(auth_payload); - if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) - { - DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed", - this->msk.ptr ? "" : "out"); - chunk_free(&auth_data); - return FALSE; - } - chunk_free(&auth_data); - - DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - other_id, auth_class_names, AUTH_CLASS_EAP); - this->auth_complete = TRUE; - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); - return TRUE; -} - -/** - * Build AUTH payload - */ -static void build_auth(private_eap_authenticator_t *this, message_t *message, - chunk_t nonce, chunk_t init) -{ - auth_payload_t *auth_payload; - identification_t *my_id; - chunk_t auth_data; - keymat_t *keymat; - - my_id = this->ike_sa->get_my_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); - - DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", - my_id, auth_class_names, AUTH_CLASS_EAP); - - auth_data = keymat->get_psk_sig(keymat, FALSE, init, nonce, - this->msk, my_id, this->reserved); - auth_payload = auth_payload_create(); - auth_payload->set_auth_method(auth_payload, AUTH_PSK); - auth_payload->set_data(auth_payload, auth_data); - message->add_payload(message, (payload_t*)auth_payload); - chunk_free(&auth_data); -} - -METHOD(authenticator_t, process_server, status_t, - private_eap_authenticator_t *this, message_t *message) -{ - eap_payload_t *eap_payload; - - if (this->eap_complete) - { - if (!verify_auth(this, message, this->sent_nonce, this->received_init)) - { - return FAILED; - } - return NEED_MORE; - } - - if (!this->method) - { - this->eap_payload = server_initiate_eap(this, TRUE); - } - else - { - eap_payload = (eap_payload_t*)message->get_payload(message, - EXTENSIBLE_AUTHENTICATION); - if (!eap_payload) - { - return FAILED; - } - this->eap_payload = server_process_eap(this, eap_payload); - } - return NEED_MORE; -} - -METHOD(authenticator_t, build_server, status_t, - private_eap_authenticator_t *this, message_t *message) -{ - if (this->eap_payload) - { - eap_code_t code; - - code = this->eap_payload->get_code(this->eap_payload); - message->add_payload(message, (payload_t*)this->eap_payload); - this->eap_payload = NULL; - if (code == EAP_FAILURE) - { - return FAILED; - } - return NEED_MORE; - } - if (this->eap_complete && this->auth_complete) - { - build_auth(this, message, this->received_nonce, this->sent_init); - return SUCCESS; - } - return FAILED; -} - -METHOD(authenticator_t, process_client, status_t, - private_eap_authenticator_t *this, message_t *message) -{ - eap_payload_t *eap_payload; - - if (this->eap_complete) - { - if (!verify_auth(this, message, this->sent_nonce, this->received_init)) - { - return FAILED; - } - if (this->require_mutual && !this->method->is_mutual(this->method)) - { /* we require mutual authentication due to EAP-only */ - u_int32_t vendor; - - DBG1(DBG_IKE, "EAP-only authentication requires a mutual and " - "MSK deriving EAP method, but %N is not", - eap_type_names, this->method->get_type(this->method, &vendor)); - return FAILED; - } - return SUCCESS; - } - - eap_payload = (eap_payload_t*)message->get_payload(message, - EXTENSIBLE_AUTHENTICATION); - if (eap_payload) - { - switch (eap_payload->get_code(eap_payload)) - { - case EAP_REQUEST: - { - this->eap_payload = client_process_eap(this, eap_payload); - if (this->eap_payload) - { - return NEED_MORE; - } - return FAILED; - } - case EAP_SUCCESS: - { - eap_type_t type; - u_int32_t vendor; - auth_cfg_t *cfg; - - if (this->method->get_msk(this->method, &this->msk) == SUCCESS) - { - this->msk = chunk_clone(this->msk); - } - type = this->method->get_type(this->method, &vendor); - if (vendor) - { - DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " - "%sMSK established", type, vendor, - this->msk.ptr ? "" : "no "); - } - else - { - DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", - eap_type_names, type, this->msk.ptr ? "" : "no "); - } - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); - if (vendor) - { - cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); - } - this->eap_complete = TRUE; - return NEED_MORE; - } - case EAP_FAILURE: - default: - { - DBG1(DBG_IKE, "received %N, EAP authentication failed", - eap_code_names, eap_payload->get_code(eap_payload)); - return FAILED; - } - } - } - return FAILED; -} - -METHOD(authenticator_t, build_client, status_t, - private_eap_authenticator_t *this, message_t *message) -{ - if (this->eap_payload) - { - message->add_payload(message, (payload_t*)this->eap_payload); - this->eap_payload = NULL; - return NEED_MORE; - } - if (this->eap_complete) - { - build_auth(this, message, this->received_nonce, this->sent_init); - return NEED_MORE; - } - return NEED_MORE; -} - -METHOD(authenticator_t, is_mutual, bool, - private_eap_authenticator_t *this) -{ - /* we don't know yet, but insist on it after EAP is complete */ - this->require_mutual = TRUE; - return TRUE; -} - -METHOD(authenticator_t, destroy, void, - private_eap_authenticator_t *this) -{ - DESTROY_IF(this->method); - DESTROY_IF(this->eap_payload); - DESTROY_IF(this->eap_identity); - chunk_free(&this->msk); - free(this); -} - -/* - * Described in header. - */ -eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]) -{ - private_eap_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build_client, - .process = _process_client, - .is_mutual = _is_mutual, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .received_init = received_init, - .received_nonce = received_nonce, - .sent_init = sent_init, - .sent_nonce = sent_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} - -/* - * Described in header. - */ -eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]) -{ - private_eap_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build_server, - .process = _process_server, - .is_mutual = _is_mutual, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .received_init = received_init, - .received_nonce = received_nonce, - .sent_init = sent_init, - .sent_nonce = sent_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} - diff --git a/src/libcharon/sa/authenticators/eap_authenticator.h b/src/libcharon/sa/authenticators/eap_authenticator.h deleted file mode 100644 index 726411a18..000000000 --- a/src/libcharon/sa/authenticators/eap_authenticator.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup eap_authenticator eap_authenticator - * @{ @ingroup authenticators - */ - -#ifndef EAP_AUTHENTICATOR_H_ -#define EAP_AUTHENTICATOR_H_ - -typedef struct eap_authenticator_t eap_authenticator_t; - -#include - -/** - * Implementation of authenticator_t using EAP authentication. - * - * Authentication using EAP involves the most complex authenticator. It stays - * alive over multiple ike_auth transactions and handles multiple EAP - * messages. - * - * @verbatim - ike_sa_init - -------------------------> - <------------------------- - followed by multiple ike_auth: - - +--------+ +--------+ - | EAP | IDi, [IDr,] SA, TS | EAP | - | client | ---------------------------> | server | - | | ID, AUTH, EAP | | - | | <--------------------------- | | - | | EAP | | - | | ---------------------------> | | - | | EAP | | - | | <--------------------------- | | - | | EAP | | - | | ---------------------------> | | - | | EAP(SUCCESS) | | - | | <--------------------------- | | - | | AUTH | | If EAP establishes - | | ---------------------------> | | a session key, AUTH - | | AUTH, SA, TS | | payloads use this - | | <--------------------------- | | key, not SK_pi/pr - +--------+ +--------+ - - @endverbatim - */ -struct eap_authenticator_t { - - /** - * Implemented authenticator_t interface. - */ - authenticator_t authenticator; -}; - -/** - * Create an authenticator to authenticate against an EAP server. - * - * @param ike_sa associated ike_sa - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return EAP authenticator - */ -eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]); - -/** - * Create an authenticator to authenticate EAP clients. - * - * @param ike_sa associated ike_sa - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return EAP authenticator - */ -eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init, - char reserved[3]); - -#endif /** EAP_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/psk_authenticator.c b/src/libcharon/sa/authenticators/psk_authenticator.c deleted file mode 100644 index 21fc0f9b8..000000000 --- a/src/libcharon/sa/authenticators/psk_authenticator.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "psk_authenticator.h" - -#include -#include - -typedef struct private_psk_authenticator_t private_psk_authenticator_t; - -/** - * Private data of an psk_authenticator_t object. - */ -struct private_psk_authenticator_t { - - /** - * Public authenticator_t interface. - */ - psk_authenticator_t public; - - /** - * Assigned IKE_SA - */ - ike_sa_t *ike_sa; - - /** - * nonce to include in AUTH calculation - */ - chunk_t nonce; - - /** - * IKE_SA_INIT message data to include in AUTH calculation - */ - chunk_t ike_sa_init; - - /** - * Reserved bytes of ID payload - */ - char reserved[3]; -}; - -METHOD(authenticator_t, build, status_t, - private_psk_authenticator_t *this, message_t *message) -{ - identification_t *my_id, *other_id; - auth_payload_t *auth_payload; - shared_key_t *key; - chunk_t auth_data; - keymat_t *keymat; - - keymat = this->ike_sa->get_keymat(this->ike_sa); - my_id = this->ike_sa->get_my_id(this->ike_sa); - other_id = this->ike_sa->get_other_id(this->ike_sa); - DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", - my_id, auth_method_names, AUTH_PSK); - key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, other_id); - if (key == NULL) - { - DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id); - return NOT_FOUND; - } - auth_data = keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, - this->nonce, key->get_key(key), my_id, this->reserved); - key->destroy(key); - DBG2(DBG_IKE, "successfully created shared key MAC"); - auth_payload = auth_payload_create(); - auth_payload->set_auth_method(auth_payload, AUTH_PSK); - auth_payload->set_data(auth_payload, auth_data); - chunk_free(&auth_data); - message->add_payload(message, (payload_t*)auth_payload); - - return SUCCESS; -} - -METHOD(authenticator_t, process, status_t, - private_psk_authenticator_t *this, message_t *message) -{ - chunk_t auth_data, recv_auth_data; - identification_t *my_id, *other_id; - auth_payload_t *auth_payload; - auth_cfg_t *auth; - shared_key_t *key; - enumerator_t *enumerator; - bool authenticated = FALSE; - int keys_found = 0; - keymat_t *keymat; - - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - if (!auth_payload) - { - return FAILED; - } - keymat = this->ike_sa->get_keymat(this->ike_sa); - recv_auth_data = auth_payload->get_data(auth_payload); - my_id = this->ike_sa->get_my_id(this->ike_sa); - other_id = this->ike_sa->get_other_id(this->ike_sa); - enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, - SHARED_IKE, my_id, other_id); - while (!authenticated && enumerator->enumerate(enumerator, &key, NULL, NULL)) - { - keys_found++; - - auth_data = keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, - this->nonce, key->get_key(key), other_id, this->reserved); - if (auth_data.len && chunk_equals(auth_data, recv_auth_data)) - { - DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - other_id, auth_method_names, AUTH_PSK); - authenticated = TRUE; - } - chunk_free(&auth_data); - } - enumerator->destroy(enumerator); - - if (!authenticated) - { - if (keys_found == 0) - { - DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id); - return NOT_FOUND; - } - DBG1(DBG_IKE, "tried %d shared key%s for '%Y' - '%Y', but MAC mismatched", - keys_found, keys_found == 1 ? "" : "s", my_id, other_id); - return FAILED; - } - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); - return SUCCESS; -} - -METHOD(authenticator_t, destroy, void, - private_psk_authenticator_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init, - char reserved[3]) -{ - private_psk_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build, - .process = (void*)return_failed, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .ike_sa_init = sent_init, - .nonce = received_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} - -/* - * Described in header. - */ -psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init, - char reserved[3]) -{ - private_psk_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = (void*)return_failed, - .process = _process, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .ike_sa_init = received_init, - .nonce = sent_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} - diff --git a/src/libcharon/sa/authenticators/psk_authenticator.h b/src/libcharon/sa/authenticators/psk_authenticator.h deleted file mode 100644 index 8cf1a0f98..000000000 --- a/src/libcharon/sa/authenticators/psk_authenticator.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup psk_authenticator psk_authenticator - * @{ @ingroup authenticators - */ - -#ifndef PSK_AUTHENTICATOR_H_ -#define PSK_AUTHENTICATOR_H_ - -typedef struct psk_authenticator_t psk_authenticator_t; - -#include - -/** - * Implementation of authenticator_t using pre-shared keys. - */ -struct psk_authenticator_t { - - /** - * Implemented authenticator_t interface. - */ - authenticator_t authenticator; -}; - -/** - * Create an authenticator to build PSK signatures. - * - * @param ike_sa associated ike_sa - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return PSK authenticator - */ -psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init, - char reserved[3]); - -/** - * Create an authenticator to verify PSK signatures. - * - * @param ike_sa associated ike_sa - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return PSK authenticator - */ -psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init, - char reserved[3]); - -#endif /** PSK_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.c b/src/libcharon/sa/authenticators/pubkey_authenticator.c deleted file mode 100644 index 247891670..000000000 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "pubkey_authenticator.h" - -#include -#include - -typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t; - -/** - * Private data of an pubkey_authenticator_t object. - */ -struct private_pubkey_authenticator_t { - - /** - * Public authenticator_t interface. - */ - pubkey_authenticator_t public; - - /** - * Assigned IKE_SA - */ - ike_sa_t *ike_sa; - - /** - * nonce to include in AUTH calculation - */ - chunk_t nonce; - - /** - * IKE_SA_INIT message data to include in AUTH calculation - */ - chunk_t ike_sa_init; - - /** - * Reserved bytes of ID payload - */ - char reserved[3]; -}; - -METHOD(authenticator_t, build, status_t, - private_pubkey_authenticator_t *this, message_t *message) -{ - chunk_t octets, auth_data; - status_t status = FAILED; - private_key_t *private; - identification_t *id; - auth_cfg_t *auth; - auth_payload_t *auth_payload; - auth_method_t auth_method; - signature_scheme_t scheme; - keymat_t *keymat; - - id = this->ike_sa->get_my_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth); - if (private == NULL) - { - DBG1(DBG_IKE, "no private key found for '%Y'", id); - return NOT_FOUND; - } - - switch (private->get_type(private)) - { - case KEY_RSA: - /* we currently use always SHA1 for signatures, - * TODO: support other hashes depending on configuration/auth */ - scheme = SIGN_RSA_EMSA_PKCS1_SHA1; - auth_method = AUTH_RSA; - break; - case KEY_ECDSA: - /* we try to deduct the signature scheme from the keysize */ - switch (private->get_keysize(private)) - { - case 256: - scheme = SIGN_ECDSA_256; - auth_method = AUTH_ECDSA_256; - break; - case 384: - scheme = SIGN_ECDSA_384; - auth_method = AUTH_ECDSA_384; - break; - case 521: - scheme = SIGN_ECDSA_521; - auth_method = AUTH_ECDSA_521; - break; - default: - DBG1(DBG_IKE, "%d bit ECDSA private key size not supported", - private->get_keysize(private)); - return status; - } - break; - default: - DBG1(DBG_IKE, "private key of type %N not supported", - key_type_names, private->get_type(private)); - return status; - } - keymat = this->ike_sa->get_keymat(this->ike_sa); - octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, - this->nonce, id, this->reserved); - if (private->sign(private, scheme, octets, &auth_data)) - { - auth_payload = auth_payload_create(); - auth_payload->set_auth_method(auth_payload, auth_method); - auth_payload->set_data(auth_payload, auth_data); - chunk_free(&auth_data); - message->add_payload(message, (payload_t*)auth_payload); - status = SUCCESS; - } - DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, - auth_method_names, auth_method, - (status == SUCCESS)? "successful":"failed"); - chunk_free(&octets); - private->destroy(private); - - return status; -} - -METHOD(authenticator_t, process, status_t, - private_pubkey_authenticator_t *this, message_t *message) -{ - public_key_t *public; - auth_method_t auth_method; - auth_payload_t *auth_payload; - chunk_t auth_data, octets; - identification_t *id; - auth_cfg_t *auth, *current_auth; - enumerator_t *enumerator; - key_type_t key_type = KEY_ECDSA; - signature_scheme_t scheme; - status_t status = NOT_FOUND; - keymat_t *keymat; - - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - if (!auth_payload) - { - return FAILED; - } - auth_method = auth_payload->get_auth_method(auth_payload); - switch (auth_method) - { - case AUTH_RSA: - /* We currently accept SHA1 signatures only - * TODO: allow other hash algorithms and note it in "auth" */ - key_type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_SHA1; - break; - case AUTH_ECDSA_256: - scheme = SIGN_ECDSA_256; - break; - case AUTH_ECDSA_384: - scheme = SIGN_ECDSA_384; - break; - case AUTH_ECDSA_521: - scheme = SIGN_ECDSA_521; - break; - default: - return INVALID_ARG; - } - auth_data = auth_payload->get_data(auth_payload); - id = this->ike_sa->get_other_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); - octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init, - this->nonce, id, this->reserved); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, - key_type, id, auth); - while (enumerator->enumerate(enumerator, &public, ¤t_auth)) - { - if (public->verify(public, scheme, octets, auth_data)) - { - DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - id, auth_method_names, auth_method); - status = SUCCESS; - auth->merge(auth, current_auth, FALSE); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - break; - } - else - { - status = FAILED; - DBG1(DBG_IKE, "signature validation failed, looking for another key"); - } - } - enumerator->destroy(enumerator); - chunk_free(&octets); - if (status == NOT_FOUND) - { - DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", - key_type_names, key_type, id); - } - return status; -} - -METHOD(authenticator_t, destroy, void, - private_pubkey_authenticator_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init, - char reserved[3]) -{ - private_pubkey_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build, - .process = (void*)return_failed, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .ike_sa_init = sent_init, - .nonce = received_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} - -/* - * Described in header. - */ -pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init, - char reserved[3]) -{ - private_pubkey_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = (void*)return_failed, - .process = _process, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .ike_sa_init = received_init, - .nonce = sent_nonce, - ); - memcpy(this->reserved, reserved, sizeof(this->reserved)); - - return &this->public; -} diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.h b/src/libcharon/sa/authenticators/pubkey_authenticator.h deleted file mode 100644 index 4c3937ecc..000000000 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup pubkey_authenticator pubkey_authenticator - * @{ @ingroup authenticators - */ - -#ifndef PUBKEY_AUTHENTICATOR_H_ -#define PUBKEY_AUTHENTICATOR_H_ - -typedef struct pubkey_authenticator_t pubkey_authenticator_t; - -#include - -/** - * Implementation of authenticator_t using public key authenitcation. - */ -struct pubkey_authenticator_t { - - /** - * Implemented authenticator_t interface. - */ - authenticator_t authenticator; -}; - -/** - * Create an authenticator to build public key signatures. - * - * @param ike_sa associated ike_sa - * @param received_nonce nonce received in IKE_SA_INIT - * @param sent_init sent IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return public key authenticator - */ -pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init, - char reserved[3]); - -/** - * Create an authenticator to verify public key signatures. - * - * @param ike_sa associated ike_sa - * @param sent_nonce nonce sent in IKE_SA_INIT - * @param received_init received IKE_SA_INIT message data - * @param reserved reserved bytes of ID payload - * @return public key authenticator - */ -pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init, - char reserved[3]); - -#endif /** PUBKEY_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 2130a5998..1245734c9 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -123,6 +123,11 @@ struct private_child_sa_t { */ child_sa_state_t state; + /** + * TRUE if this CHILD_SA is used to install trap policies + */ + bool trap; + /** * Specifies if UDP encapsulation is enabled (NAT traversal) */ @@ -526,6 +531,16 @@ METHOD(child_sa_t, get_usestats, void, } } +METHOD(child_sa_t, get_mark, mark_t, + private_child_sa_t *this, bool inbound) +{ + if (inbound) + { + return this->mark_in; + } + return this->mark_out; +} + METHOD(child_sa_t, get_lifetime, time_t, private_child_sa_t *this, bool hard) { @@ -617,7 +632,14 @@ METHOD(child_sa_t, install, status_t, now = time_monotonic(NULL); if (lifetime->time.rekey) { - this->rekey_time = now + lifetime->time.rekey; + if (this->rekey_time) + { + this->rekey_time = min(this->rekey_time, now + lifetime->time.rekey); + } + else + { + this->rekey_time = now + lifetime->time.rekey; + } } if (lifetime->time.life) { @@ -757,8 +779,11 @@ METHOD(child_sa_t, add_policies, status_t, other_sa.ah.spi = this->other_spi; } - priority = this->state == CHILD_CREATED ? POLICY_PRIORITY_ROUTED - : POLICY_PRIORITY_DEFAULT; + /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD + * entry) we install a trap policy */ + this->trap = this->state == CHILD_CREATED; + priority = this->trap ? POLICY_PRIORITY_ROUTED + : POLICY_PRIORITY_DEFAULT; /* enumerate pairs of traffic selectors */ enumerator = create_policy_enumerator(this); @@ -787,16 +812,25 @@ METHOD(child_sa_t, add_policies, status_t, enumerator->destroy(enumerator); } - if (status == SUCCESS && this->state == CHILD_CREATED) - { /* switch to routed state if no SAD entry set up */ + if (status == SUCCESS && this->trap) + { set_state(this, CHILD_ROUTED); } return status; } +/** + * Callback to reinstall a virtual IP + */ +static void reinstall_vip(host_t *vip, host_t *me) +{ + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + hydra->kernel_interface->add_ip(hydra->kernel_interface, vip, me); +} + METHOD(child_sa_t, update, status_t, - private_child_sa_t *this, host_t *me, host_t *other, host_t *vip, - bool encap) + private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips, + bool encap) { child_sa_state_t old; bool transport_proxy_mode; @@ -902,13 +936,7 @@ METHOD(child_sa_t, update, status_t, /* we reinstall the virtual IP to handle interface roaming * correctly */ - if (vip) - { - hydra->kernel_interface->del_ip(hydra->kernel_interface, - vip); - hydra->kernel_interface->add_ip(hydra->kernel_interface, - vip, me); - } + vips->invoke_function(vips, (void*)reinstall_vip, me); /* reinstall updated policies */ install_policies_internal(this, me, other, my_ts, other_ts, @@ -960,8 +988,7 @@ METHOD(child_sa_t, destroy, void, traffic_selector_t *my_ts, *other_ts; policy_priority_t priority; - priority = this->state == CHILD_ROUTED ? POLICY_PRIORITY_ROUTED - : POLICY_PRIORITY_DEFAULT; + priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT; set_state(this, CHILD_DESTROYING); @@ -1038,6 +1065,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .set_proposal = _set_proposal, .get_lifetime = _get_lifetime, .get_usestats = _get_usestats, + .get_mark = _get_mark, .has_encap = _has_encap, .get_ipcomp = _get_ipcomp, .set_ipcomp = _set_ipcomp, @@ -1079,6 +1107,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, this->reqid = rekey ? rekey : ++reqid; } + if (this->mark_in.value == MARK_REQID) + { + this->mark_in.value = this->reqid; + } + if (this->mark_out.value == MARK_REQID) + { + this->mark_out.value = this->reqid; + } + /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */ if (config->get_mode(config) == MODE_TRANSPORT && config->use_proxy_mode(config)) @@ -1088,12 +1125,14 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, chunk_t addr; host_t *host; enumerator_t *enumerator; - linked_list_t *my_ts_list, *other_ts_list; + linked_list_t *my_ts_list, *other_ts_list, *list; traffic_selector_t *my_ts, *other_ts; this->mode = MODE_TRANSPORT; - my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, me); + list = linked_list_create_with_items(me, NULL); + my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, list); + list->destroy(list); enumerator = my_ts_list->create_enumerator(my_ts_list); if (enumerator->enumerate(enumerator, &my_ts)) { @@ -1114,7 +1153,9 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, enumerator->destroy(enumerator); my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy)); - other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, other); + list = linked_list_create_with_items(other, NULL); + other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, list); + list->destroy(list); enumerator = other_ts_list->create_enumerator(other_ts_list); if (enumerator->enumerate(enumerator, &other_ts)) { diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index f17ef01ac..dae3f2c18 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -274,6 +274,14 @@ struct child_sa_t { void (*get_usestats)(child_sa_t *this, bool inbound, time_t *time, u_int64_t *bytes); + /** + * Get the mark used with this CHILD_SA. + * + * @param inbound TRUE to get inbound mark, FALSE for outbound + * @return mark used with this CHILD_SA + */ + mark_t (*get_mark)(child_sa_t *this, bool inbound); + /** * Get the traffic selectors list added for one side. * @@ -338,12 +346,12 @@ struct child_sa_t { * * @param me the new local host * @param other the new remote host - * @param vip virtual IP, if any + * @param vips list of local virtual IPs * @param TRUE to use UDP encapsulation for NAT traversal * @return SUCCESS or FAILED */ status_t (*update)(child_sa_t *this, host_t *me, host_t *other, - host_t *vip, bool encap); + linked_list_t *vips, bool encap); /** * Destroys a child_sa. */ diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/connect_manager.c deleted file mode 100644 index 7b6ca430f..000000000 --- a/src/libcharon/sa/connect_manager.c +++ /dev/null @@ -1,1600 +0,0 @@ -/* - * Copyright (C) 2007-2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "connect_manager.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include - -/* base timeout - * the check interval is ME_INTERVAL */ -#define ME_INTERVAL 25 /* ms */ -/* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions - * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */ -/* number of initial retransmissions sent in short interval */ -#define ME_BOOST 2 -/* base for retransmissions */ -#define ME_RETRANS_BASE 1.8 -/* max number of retransmissions */ -#define ME_MAX_RETRANS 13 - -/* time to wait before the initiator finishes the connectivity checks after - * the first check has succeeded */ -#define ME_WAIT_TO_FINISH 1000 /* ms */ - -typedef struct private_connect_manager_t private_connect_manager_t; - -/** - * Additional private members of connect_manager_t. - */ -struct private_connect_manager_t { - /** - * Public interface of connect_manager_t. - */ - connect_manager_t public; - - /** - * Lock for exclusivly accessing the manager. - */ - mutex_t *mutex; - - /** - * Hasher to generate signatures - */ - hasher_t *hasher; - - /** - * Linked list with initiated mediated connections - */ - linked_list_t *initiated; - - /** - * Linked list with checklists (hash table with connect ID as key would - * be better). - */ - linked_list_t *checklists; -}; - -typedef enum check_state_t check_state_t; - -enum check_state_t { - CHECK_NONE, - CHECK_WAITING, - CHECK_IN_PROGRESS, - CHECK_SUCCEEDED, - CHECK_FAILED -}; - -typedef struct endpoint_pair_t endpoint_pair_t; - -/** - * An entry in the check list. - */ -struct endpoint_pair_t { - /** pair id */ - u_int32_t id; - - /** priority */ - u_int64_t priority; - - /** local endpoint */ - host_t *local; - - /** remote endpoint */ - host_t *remote; - - /** state */ - check_state_t state; - - /** number of retransmissions */ - u_int32_t retransmitted; - - /** the generated packet */ - packet_t *packet; -}; - -/** - * Destroys an endpoint pair - */ -static void endpoint_pair_destroy(endpoint_pair_t *this) -{ - DESTROY_IF(this->local); - DESTROY_IF(this->remote); - DESTROY_IF(this->packet); - free(this); -} - -/** - * Creates a new entry for the list. - */ -static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator, - endpoint_notify_t *responder, bool initiator_is_local) -{ - endpoint_pair_t *this; - - u_int32_t pi = initiator->get_priority(initiator); - u_int32_t pr = responder->get_priority(responder); - - INIT(this, - .priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) - + (pi > pr ? 1 : 0), - .local = initiator_is_local ? initiator->get_base(initiator) - : responder->get_base(responder), - .remote = initiator_is_local ? responder->get_host(responder) - : initiator->get_host(initiator), - .state = CHECK_WAITING, - ); - - this->local = this->local->clone(this->local); - this->remote = this->remote->clone(this->remote); - - return this; -} - - -typedef struct check_list_t check_list_t; - -/** - * An entry in the linked list. - */ -struct check_list_t { - - struct { - /** initiator's id */ - identification_t *id; - - /** initiator's key */ - chunk_t key; - - /** initiator's endpoints */ - linked_list_t *endpoints; - } initiator; - - struct { - /** responder's id */ - identification_t *id; - - /** responder's key */ - chunk_t key; - - /** responder's endpoints */ - linked_list_t *endpoints; - } responder; - - /** connect id */ - chunk_t connect_id; - - /** list of endpoint pairs */ - linked_list_t *pairs; - - /** pairs queued for triggered checks */ - linked_list_t *triggered; - - /** state */ - check_state_t state; - - /** TRUE if this is the initiator */ - bool is_initiator; - - /** TRUE if the initiator is finishing the checks */ - bool is_finishing; - - /** the current sender job */ - job_t *sender; - -}; - -/** - * Destroys a checklist - */ -static void check_list_destroy(check_list_t *this) -{ - DESTROY_IF(this->initiator.id); - DESTROY_IF(this->responder.id); - - chunk_free(&this->connect_id); - chunk_free(&this->initiator.key); - chunk_free(&this->responder.key); - - DESTROY_OFFSET_IF(this->initiator.endpoints, - offsetof(endpoint_notify_t, destroy)); - DESTROY_OFFSET_IF(this->responder.endpoints, - offsetof(endpoint_notify_t, destroy)); - - DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy); - /* this list contains some of the elements contained in this->pairs */ - DESTROY_IF(this->triggered); - - free(this); -} - -/** - * Creates a new checklist - */ -static check_list_t *check_list_create(identification_t *initiator, - identification_t *responder, - chunk_t connect_id, - chunk_t initiator_key, - linked_list_t *initiator_endpoints, - bool is_initiator) -{ - check_list_t *this; - - INIT(this, - .connect_id = chunk_clone(connect_id), - .initiator = { - .id = initiator->clone(initiator), - .key = chunk_clone(initiator_key), - .endpoints = initiator_endpoints->clone_offset(initiator_endpoints, - offsetof(endpoint_notify_t, clone)), - }, - .responder = { - .id = responder->clone(responder), - }, - .pairs = linked_list_create(), - .triggered = linked_list_create(), - .state = CHECK_NONE, - .is_initiator = is_initiator, - ); - - return this; -} - -typedef struct initiated_t initiated_t; - -/** - * For an initiator, the data stored about initiated mediation connections - */ -struct initiated_t { - /** my id */ - identification_t *id; - - /** peer id */ - identification_t *peer_id; - - /** list of mediated sas */ - linked_list_t *mediated; -}; - -/** - * Destroys a queued initiation - */ -static void initiated_destroy(initiated_t *this) -{ - DESTROY_IF(this->id); - DESTROY_IF(this->peer_id); - this->mediated->destroy_offset(this->mediated, - offsetof(ike_sa_id_t, destroy)); - free(this); -} - -/** - * Creates a queued initiation - */ -static initiated_t *initiated_create(identification_t *id, - identification_t *peer_id) -{ - initiated_t *this; - - INIT(this, - .id = id->clone(id), - .peer_id = peer_id->clone(peer_id), - .mediated = linked_list_create(), - ); - - return this; -} - - -typedef struct check_t check_t; - -/** - * Data exchanged in a connectivity check - */ -struct check_t { - /** message id */ - u_int32_t mid; - - /** source of the connectivity check */ - host_t *src; - - /** destination of the connectivity check */ - host_t *dst; - - /** connect id */ - chunk_t connect_id; - - /** endpoint */ - endpoint_notify_t *endpoint; - - /** raw endpoint payload (to verify the signature) */ - chunk_t endpoint_raw; - - /** connect auth */ - chunk_t auth; -}; - -/** - * Destroys a connectivity check - */ -static void check_destroy(check_t *this) -{ - chunk_free(&this->connect_id); - chunk_free(&this->endpoint_raw); - chunk_free(&this->auth); - DESTROY_IF(this->src); - DESTROY_IF(this->dst); - DESTROY_IF(this->endpoint); - free(this); -} - -/** - * Creates a new connectivity check - */ -static check_t *check_create() -{ - check_t *this; - - INIT(this, - .mid = 0, - ); - - return this; -} - -typedef struct callback_data_t callback_data_t; - -/** - * Data required by several callback jobs used in this file - */ -struct callback_data_t { - /** connect manager */ - private_connect_manager_t *connect_manager; - - /** connect id */ - chunk_t connect_id; - - /** message (pair) id */ - u_int32_t mid; -}; - -/** - * Destroys a callback data object - */ -static void callback_data_destroy(callback_data_t *this) -{ - chunk_free(&this->connect_id); - free(this); -} - -/** - * Creates a new callback data object - */ -static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager, - chunk_t connect_id) -{ - callback_data_t *this; - INIT(this, - .connect_manager = connect_manager, - .connect_id = chunk_clone(connect_id), - .mid = 0, - ); - return this; -} - -/** - * Creates a new retransmission data object - */ -static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager, - chunk_t connect_id, u_int32_t mid) -{ - callback_data_t *this = callback_data_create(connect_manager, connect_id); - this->mid = mid; - return this; -} - -typedef struct initiate_data_t initiate_data_t; - -/** - * Data required by the initiate mediated - */ -struct initiate_data_t { - /** checklist */ - check_list_t *checklist; - - /** waiting mediated connections */ - initiated_t *initiated; -}; - -/** - * Destroys a initiate data object - */ -static void initiate_data_destroy(initiate_data_t *this) -{ - check_list_destroy(this->checklist); - initiated_destroy(this->initiated); - free(this); -} - -/** - * Creates a new initiate data object - */ -static initiate_data_t *initiate_data_create(check_list_t *checklist, - initiated_t *initiated) -{ - initiate_data_t *this; - INIT(this, - .checklist = checklist, - .initiated = initiated, - ); - return this; -} - -/** - * Find an initiated connection by the peers' ids - */ -static bool match_initiated_by_ids(initiated_t *current, identification_t *id, - identification_t *peer_id) -{ - return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id); -} - -static status_t get_initiated_by_ids(private_connect_manager_t *this, - identification_t *id, - identification_t *peer_id, - initiated_t **initiated) -{ - return this->initiated->find_first(this->initiated, - (linked_list_match_t)match_initiated_by_ids, - (void**)initiated, id, peer_id); -} - -/** - * Removes data about initiated connections - */ -static void remove_initiated(private_connect_manager_t *this, - initiated_t *initiated) -{ - enumerator_t *enumerator; - initiated_t *current; - - enumerator = this->initiated->create_enumerator(this->initiated); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - if (current == initiated) - { - this->initiated->remove_at(this->initiated, enumerator); - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * Find the checklist with a specific connect ID - */ -static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id) -{ - return chunk_equals(*connect_id, current->connect_id); -} - -static status_t get_checklist_by_id(private_connect_manager_t *this, - chunk_t connect_id, - check_list_t **check_list) -{ - return this->checklists->find_first(this->checklists, - (linked_list_match_t)match_checklist_by_id, - (void**)check_list, &connect_id); -} - -/** - * Removes a checklist - */ -static void remove_checklist(private_connect_manager_t *this, - check_list_t *checklist) -{ - enumerator_t *enumerator; - check_list_t *current; - - enumerator = this->checklists->create_enumerator(this->checklists); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - if (current == checklist) - { - this->checklists->remove_at(this->checklists, enumerator); - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * Checks if a list of endpoint_notify_t contains a certain host_t - */ -static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host) -{ - return host->equals(host, current->get_host(current)); -} - -static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, - endpoint_notify_t **endpoint) -{ - return endpoints->find_first(endpoints, - (linked_list_match_t)match_endpoint_by_host, - (void**)endpoint, host); -} - -/** - * Inserts an endpoint pair into a list of pairs ordered by priority (high to low) - */ -static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) -{ - enumerator_t *enumerator = pairs->create_enumerator(pairs); - endpoint_pair_t *current; - while (enumerator->enumerate(enumerator, (void**)¤t) && - current->priority >= pair->priority) - { - continue; - } - pairs->insert_before(pairs, enumerator, pair); - enumerator->destroy(enumerator); -} - -/** - * Searches a list of endpoint_pair_t for a pair with specific host_ts - */ -static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, - host_t *remote) -{ - return local->equals(local, current->local) && remote->equals(remote, current->remote); -} - -static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, - host_t *remote, endpoint_pair_t **pair) -{ - return pairs->find_first(pairs, (linked_list_match_t)match_pair_by_hosts, - (void**)pair, local, remote); -} - -static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id) -{ - return current->id == *id; -} - -/** - * Searches for a pair with a specific id - */ -static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, - endpoint_pair_t **pair) -{ - return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_pair_by_id, - (void**)pair, &id); -} - -static bool match_succeeded_pair(endpoint_pair_t *current) -{ - return current->state == CHECK_SUCCEEDED; -} - -/** - * Returns the best pair of state CHECK_SUCCEEDED from a checklist. - */ -static status_t get_best_valid_pair(check_list_t *checklist, - endpoint_pair_t **pair) -{ - return checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_succeeded_pair, - (void**)pair); -} - -static bool match_waiting_pair(endpoint_pair_t *current) -{ - return current->state == CHECK_WAITING; -} - -/** - * Returns and *removes* the first triggered pair in state CHECK_WAITING. - */ -static status_t get_triggered_pair(check_list_t *checklist, - endpoint_pair_t **pair) -{ - enumerator_t *enumerator; - endpoint_pair_t *current; - status_t status = NOT_FOUND; - - enumerator = checklist->triggered->create_enumerator(checklist->triggered); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - checklist->triggered->remove_at(checklist->triggered, enumerator); - - if (current->state == CHECK_WAITING) - { - if (pair) - { - *pair = current; - } - status = SUCCESS; - break; - } - } - enumerator->destroy(enumerator); - - return status; -} - -/** - * Prints all the pairs on a checklist - */ -static void print_checklist(check_list_t *checklist) -{ - enumerator_t *enumerator; - endpoint_pair_t *current; - - DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id); - enumerator = checklist->pairs->create_enumerator(checklist->pairs); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote, - current->priority); - } - enumerator->destroy(enumerator); -} - -/** - * Prunes identical pairs with lower priority from the list - * Note: this function also numbers the remaining pairs serially - */ -static void prune_pairs(linked_list_t *pairs) -{ - enumerator_t *enumerator, *search; - endpoint_pair_t *current, *other; - u_int32_t id = 0; - - enumerator = pairs->create_enumerator(pairs); - search = pairs->create_enumerator(pairs); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - current->id = ++id; - - while (search->enumerate(search, (void**)&other)) - { - if (current == other) - { - continue; - } - - if (current->local->equals(current->local, other->local) && - current->remote->equals(current->remote, other->remote)) - { - /* since the list of pairs is sorted by priority in descending - * order, and we iterate the list from the beginning, we are - * sure that the priority of 'other' is lower than that of - * 'current', remove it */ - DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d", - other->local, other->remote, other->priority); - pairs->remove_at(pairs, search); - endpoint_pair_destroy(other); - } - } - pairs->reset_enumerator(pairs, search); - } - search->destroy(search); - enumerator->destroy(enumerator); -} - -/** - * Builds a list of endpoint pairs - */ -static void build_pairs(check_list_t *checklist) -{ - /* FIXME: limit endpoints and pairs */ - enumerator_t *enumerator_i, *enumerator_r; - endpoint_notify_t *initiator, *responder; - - enumerator_i = checklist->initiator.endpoints->create_enumerator( - checklist->initiator.endpoints); - while (enumerator_i->enumerate(enumerator_i, (void**)&initiator)) - { - enumerator_r = checklist->responder.endpoints->create_enumerator( - checklist->responder.endpoints); - while (enumerator_r->enumerate(enumerator_r, (void**)&responder)) - { - if (initiator->get_family(initiator) != responder->get_family(responder)) - { - continue; - } - - insert_pair_by_priority(checklist->pairs, endpoint_pair_create( - initiator, responder, checklist->is_initiator)); - } - enumerator_r->destroy(enumerator_r); - } - enumerator_i->destroy(enumerator_i); - - print_checklist(checklist); - - prune_pairs(checklist->pairs); -} - -/** - * Processes the payloads of a connectivity check and returns the extracted data - */ -static status_t process_payloads(message_t *message, check_t *check) -{ - enumerator_t *enumerator; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) != NOTIFY) - { - DBG1(DBG_IKE, "ignoring payload of type '%N' while processing " - "connectivity check", payload_type_names, - payload->get_type(payload)); - continue; - } - - notify_payload_t *notify = (notify_payload_t*)payload; - - switch (notify->get_notify_type(notify)) - { - case ME_ENDPOINT: - { - if (check->endpoint) - { - DBG1(DBG_IKE, "connectivity check contains multiple " - "ME_ENDPOINT notifies"); - break; - } - - endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify); - if (!endpoint) - { - DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify"); - break; - } - check->endpoint = endpoint; - check->endpoint_raw = chunk_clone(notify->get_notification_data(notify)); - DBG2(DBG_IKE, "received ME_ENDPOINT notify"); - break; - } - case ME_CONNECTID: - { - if (check->connect_id.ptr) - { - DBG1(DBG_IKE, "connectivity check contains multiple " - "ME_CONNECTID notifies"); - break; - } - check->connect_id = chunk_clone(notify->get_notification_data(notify)); - DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id); - break; - } - case ME_CONNECTAUTH: - { - if (check->auth.ptr) - { - DBG1(DBG_IKE, "connectivity check contains multiple " - "ME_CONNECTAUTH notifies"); - break; - } - check->auth = chunk_clone(notify->get_notification_data(notify)); - DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth); - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); - - if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr) - { - DBG1(DBG_IKE, "at least one required payload was missing from the " - "connectivity check"); - return FAILED; - } - - return SUCCESS; -} - -/** - * Builds the signature for a connectivity check - */ -static chunk_t build_signature(private_connect_manager_t *this, - check_list_t *checklist, check_t *check, bool outbound) -{ - u_int32_t mid; - chunk_t mid_chunk, key_chunk, sig_chunk; - chunk_t sig_hash; - - mid = htonl(check->mid); - mid_chunk = chunk_from_thing(mid); - - key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound) - ? checklist->initiator.key : checklist->responder.key; - - /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */ - sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, - check->endpoint_raw, key_chunk); - this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash); - DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk); - DBG3(DBG_IKE, "sig_hash %#B", &sig_hash); - - chunk_free(&sig_chunk); - return sig_hash; -} - -static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair); -static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time); -static void finish_checks(private_connect_manager_t *this, check_list_t *checklist); - -/** - * After one of the initiator's pairs has succeeded we finish the checks without - * waiting for all the timeouts - */ -static job_requeue_t initiator_finish(callback_data_t *data) -{ - private_connect_manager_t *this = data->connect_manager; - - this->mutex->lock(this->mutex); - - check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish " - "connectivity checks", &data->connect_id); - this->mutex->unlock(this->mutex); - return JOB_REQUEUE_NONE; - } - - finish_checks(this, checklist); - - this->mutex->unlock(this->mutex); - - return JOB_REQUEUE_NONE; -} - -/** - * Updates the state of the whole checklist - */ -static void update_checklist_state(private_connect_manager_t *this, - check_list_t *checklist) -{ - enumerator_t *enumerator; - endpoint_pair_t *current; - bool in_progress = FALSE, succeeded = FALSE; - - enumerator = checklist->pairs->create_enumerator(checklist->pairs); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - switch(current->state) - { - case CHECK_WAITING: - /* at least one is still waiting -> checklist remains - * in waiting state */ - enumerator->destroy(enumerator); - return; - case CHECK_IN_PROGRESS: - in_progress = TRUE; - break; - case CHECK_SUCCEEDED: - succeeded = TRUE; - break; - default: - break; - } - } - enumerator->destroy(enumerator); - - if (checklist->is_initiator && succeeded && !checklist->is_finishing) - { - /* instead of waiting until all checks have finished (i.e. all - * retransmissions have failed) the initiator finishes the checks - * right after the first check has succeeded. to allow a probably - * better pair to succeed, we still wait a certain time */ - DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", - &checklist->connect_id); - - callback_data_t *data = callback_data_create(this, checklist->connect_id); - job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - lib->scheduler->schedule_job_ms(lib->scheduler, job, ME_WAIT_TO_FINISH); - checklist->is_finishing = TRUE; - } - - if (in_progress) - { - checklist->state = CHECK_IN_PROGRESS; - } - else if (succeeded) - { - checklist->state = CHECK_SUCCEEDED; - } - else - { - checklist->state = CHECK_FAILED; - } -} - -/** - * This function is triggered for each sent check after a specific timeout - */ -static job_requeue_t retransmit(callback_data_t *data) -{ - private_connect_manager_t *this = data->connect_manager; - - this->mutex->lock(this->mutex); - - check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit " - "connectivity check", &data->connect_id); - this->mutex->unlock(this->mutex); - return JOB_REQUEUE_NONE; - } - - endpoint_pair_t *pair; - if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS) - { - DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit " - "connectivity check", data->mid); - goto retransmit_end; - } - - if (pair->state != CHECK_IN_PROGRESS) - { - DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't " - "retransmit the connectivity check", data->mid, pair->state); - goto retransmit_end; - } - - if (++pair->retransmitted > ME_MAX_RETRANS) - { - DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions", - data->mid, ME_MAX_RETRANS); - pair->state = CHECK_FAILED; - goto retransmit_end; - } - - charon->sender->send(charon->sender, pair->packet->clone(pair->packet)); - - queue_retransmission(this, checklist, pair); - -retransmit_end: - update_checklist_state(this, checklist); - - switch(checklist->state) - { - case CHECK_SUCCEEDED: - case CHECK_FAILED: - finish_checks(this, checklist); - break; - default: - break; - } - - this->mutex->unlock(this->mutex); - - /* we reschedule it manually */ - return JOB_REQUEUE_NONE; -} - -/** - * Queues a retransmission job - */ -static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair) -{ - callback_data_t *data = retransmit_data_create(this, checklist->connect_id, pair->id); - job_t *job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - - u_int32_t retransmission = pair->retransmitted + 1; - u_int32_t rto = ME_INTERVAL; - if (retransmission > ME_BOOST) - { - rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST)); - } - DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", - retransmission, pair->id, rto); - - lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)job, rto); -} - -/** - * Sends a check - */ -static void send_check(private_connect_manager_t *this, check_list_t *checklist, - check_t *check, endpoint_pair_t *pair, bool request) -{ - message_t *message = message_create(); - message->set_message_id(message, check->mid); - message->set_exchange_type(message, INFORMATIONAL); - message->set_request(message, request); - message->set_destination(message, check->dst->clone(check->dst)); - message->set_source(message, check->src->clone(check->src)); - - ike_sa_id_t *ike_sa_id = ike_sa_id_create(0, 0, request); - message->set_ike_sa_id(message, ike_sa_id); - ike_sa_id->destroy(ike_sa_id); - - message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id); - DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id); - - notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint); - check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint)); - message->add_payload(message, (payload_t*)endpoint); - DBG2(DBG_IKE, "send ME_ENDPOINT notify"); - - check->auth = build_signature(this, checklist, check, TRUE); - message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth); - DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth); - - packet_t *packet; - if (message->generate(message, NULL, &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet->clone(packet)); - - if (request) - { - DESTROY_IF(pair->packet); - pair->packet = packet; - pair->retransmitted = 0; - queue_retransmission(this, checklist, pair); - } - else - { - packet->destroy(packet); - } - } - message->destroy(message); -} - -/** - * Queues a triggered check - */ -static void queue_triggered_check(private_connect_manager_t *this, - check_list_t *checklist, endpoint_pair_t *pair) -{ - DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id); - pair->state = CHECK_WAITING; - checklist->triggered->insert_last(checklist->triggered, pair); - - if (!checklist->sender) - { - /* if the sender is not running we restart it */ - schedule_checks(this, checklist, ME_INTERVAL); - } -} - -/** - * This function is triggered for each checklist at a specific interval - */ -static job_requeue_t sender(callback_data_t *data) -{ - private_connect_manager_t *this = data->connect_manager; - - this->mutex->lock(this->mutex); - - check_list_t *checklist; - if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send " - "connectivity check", &data->connect_id); - this->mutex->unlock(this->mutex); - return JOB_REQUEUE_NONE; - } - - /* reset the sender */ - checklist->sender = NULL; - - endpoint_pair_t *pair; - if (get_triggered_pair(checklist, &pair) != SUCCESS) - { - DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check"); - - if (checklist->pairs->find_first(checklist->pairs, - (linked_list_match_t)match_waiting_pair, - (void**)&pair) != SUCCESS) - { - this->mutex->unlock(this->mutex); - DBG1(DBG_IKE, "no pairs in waiting state, aborting"); - return JOB_REQUEUE_NONE; - } - } - else - { - DBG1(DBG_IKE, "triggered check found"); - } - - check_t *check = check_create(); - check->mid = pair->id; - check->src = pair->local->clone(pair->local); - check->dst = pair->remote->clone(pair->remote); - check->connect_id = chunk_clone(checklist->connect_id); - check->endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, NULL, - NULL); - - pair->state = CHECK_IN_PROGRESS; - - send_check(this, checklist, check, pair, TRUE); - - check_destroy(check); - - /* schedule this job again */ - schedule_checks(this, checklist, ME_INTERVAL); - - this->mutex->unlock(this->mutex); - - /* we reschedule it manually */ - return JOB_REQUEUE_NONE; -} - -/** - * Schedules checks for a checklist (time in ms) - */ -static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time) -{ - callback_data_t *data = callback_data_create(this, checklist->connect_id); - checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, data, (callback_job_cleanup_t)callback_data_destroy, NULL); - lib->scheduler->schedule_job_ms(lib->scheduler, checklist->sender, time); -} - -/** - * Initiates waiting mediated connections - */ -static job_requeue_t initiate_mediated(initiate_data_t *data) -{ - check_list_t *checklist = data->checklist; - initiated_t *initiated = data->initiated; - - endpoint_pair_t *pair; - if (get_best_valid_pair(checklist, &pair) == SUCCESS) - { - ike_sa_id_t *waiting_sa; - enumerator_t *enumerator = initiated->mediated->create_enumerator( - initiated->mediated); - while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) - { - ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa); - if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS) - { - DBG1(DBG_IKE, "establishing mediated connection failed"); - charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); - } - else - { - charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); - } - } - enumerator->destroy(enumerator); - } - else - { - /* this should (can?) not happen */ - } - - return JOB_REQUEUE_NONE; -} - -/** - * Finishes checks for a checklist - */ -static void finish_checks(private_connect_manager_t *this, check_list_t *checklist) -{ - if (checklist->is_initiator) - { - initiated_t *initiated; - if (get_initiated_by_ids(this, checklist->initiator.id, - checklist->responder.id, &initiated) == SUCCESS) - { - remove_checklist(this, checklist); - remove_initiated(this, initiated); - - initiate_data_t *data = initiate_data_create(checklist, initiated); - job_t *job = (job_t*)callback_job_create((callback_job_cb_t)initiate_mediated, data, (callback_job_cleanup_t)initiate_data_destroy, NULL); - lib->processor->queue_job(lib->processor, job); - return; - } - else - { - DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y'" - " and '%Y'", checklist->initiator.id, checklist->responder.id); - } - } -} - -/** - * Process the response to one of our requests - */ -static void process_response(private_connect_manager_t *this, check_t *check, - check_list_t *checklist) -{ - endpoint_pair_t *pair; - if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS) - { - if (pair->local->equals(pair->local, check->dst) && - pair->remote->equals(pair->remote, check->src)) - { - DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", - pair->id, pair->local, pair->remote); - pair->state = CHECK_SUCCEEDED; - } - - linked_list_t *local_endpoints = checklist->is_initiator ? - checklist->initiator.endpoints : checklist->responder.endpoints; - - endpoint_notify_t *local_endpoint; - if (endpoints_contain(local_endpoints, - check->endpoint->get_host(check->endpoint), - &local_endpoint) != SUCCESS) - { - local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, - check->endpoint->get_host(check->endpoint), pair->local); - local_endpoint->set_priority(local_endpoint, - check->endpoint->get_priority(check->endpoint)); - local_endpoints->insert_last(local_endpoints, local_endpoint); - } - - update_checklist_state(this, checklist); - - switch(checklist->state) - { - case CHECK_SUCCEEDED: - case CHECK_FAILED: - finish_checks(this, checklist); - break; - default: - break; - } - } - else - { - DBG1(DBG_IKE, "pair with id '%d' not found", check->mid); - } -} - -static void process_request(private_connect_manager_t *this, check_t *check, - check_list_t *checklist) -{ - linked_list_t *remote_endpoints = checklist->is_initiator ? - checklist->responder.endpoints : checklist->initiator.endpoints; - - endpoint_notify_t *peer_reflexive, *remote_endpoint; - peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, - check->src, NULL); - peer_reflexive->set_priority(peer_reflexive, - check->endpoint->get_priority(check->endpoint)); - - if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS) - { - remote_endpoint = peer_reflexive->clone(peer_reflexive); - remote_endpoints->insert_last(remote_endpoints, remote_endpoint); - } - - endpoint_pair_t *pair; - if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, - &pair) == SUCCESS) - { - switch(pair->state) - { - case CHECK_IN_PROGRESS: - /* prevent retransmissions */ - pair->retransmitted = ME_MAX_RETRANS; - /* FIXME: we should wait to the next rto to send the triggered - * check */ - /* fall-through */ - case CHECK_WAITING: - case CHECK_FAILED: - queue_triggered_check(this, checklist, pair); - break; - case CHECK_SUCCEEDED: - default: - break; - } - } - else - { - endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL); - - endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint; - endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint; - - pair = endpoint_pair_create(initiator, responder, checklist->is_initiator); - pair->id = checklist->pairs->get_count(checklist->pairs) + 1; - - insert_pair_by_priority(checklist->pairs, pair); - - queue_triggered_check(this, checklist, pair); - - local_endpoint->destroy(local_endpoint); - } - - check_t *response = check_create(); - - response->mid = check->mid; - response->src = check->dst->clone(check->dst); - response->dst = check->src->clone(check->src); - response->connect_id = chunk_clone(check->connect_id); - response->endpoint = peer_reflexive; - - send_check(this, checklist, response, pair, FALSE); - - check_destroy(response); -} - -METHOD(connect_manager_t, process_check, void, - private_connect_manager_t *this, message_t *message) -{ - if (message->parse_body(message, NULL) != SUCCESS) - { - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", - exchange_type_names, message->get_exchange_type(message), - message->get_request(message) ? "request" : "response", - message->get_message_id(message)); - return; - } - - check_t *check = check_create(); - check->mid = message->get_message_id(message); - check->src = message->get_source(message); - check->src = check->src->clone(check->src); - check->dst = message->get_destination(message); - check->dst = check->dst->clone(check->dst); - - if (process_payloads(message, check) != SUCCESS) - { - DBG1(DBG_IKE, "invalid connectivity check %s received", - message->get_request(message) ? "request" : "response"); - check_destroy(check); - return; - } - - this->mutex->lock(this->mutex); - - check_list_t *checklist; - if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found", - &check->connect_id); - check_destroy(check); - this->mutex->unlock(this->mutex); - return; - } - - chunk_t sig = build_signature(this, checklist, check, FALSE); - if (!chunk_equals(sig, check->auth)) - { - DBG1(DBG_IKE, "connectivity check verification failed"); - check_destroy(check); - chunk_free(&sig); - this->mutex->unlock(this->mutex); - return; - } - chunk_free(&sig); - - if (message->get_request(message)) - { - process_request(this, check, checklist); - } - else - { - process_response(this, check, checklist); - } - - this->mutex->unlock(this->mutex); - - check_destroy(check); -} - -METHOD(connect_manager_t, check_and_register, bool, - private_connect_manager_t *this, identification_t *id, - identification_t *peer_id, ike_sa_id_t *mediated_sa) -{ - initiated_t *initiated; - bool already_there = TRUE; - - this->mutex->lock(this->mutex); - - if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) - { - DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", - peer_id); - initiated = initiated_create(id, peer_id); - this->initiated->insert_last(this->initiated, initiated); - already_there = FALSE; - } - - if (initiated->mediated->find_first(initiated->mediated, - (linked_list_match_t)mediated_sa->equals, - NULL, mediated_sa) != SUCCESS) - { - initiated->mediated->insert_last(initiated->mediated, - mediated_sa->clone(mediated_sa)); - } - - this->mutex->unlock(this->mutex); - - return already_there; -} - -METHOD(connect_manager_t, check_and_initiate, void, - private_connect_manager_t *this, ike_sa_id_t *mediation_sa, - identification_t *id, identification_t *peer_id) -{ - initiated_t *initiated; - - this->mutex->lock(this->mutex); - - if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) - { - DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id); - this->mutex->unlock(this->mutex); - return; - } - - ike_sa_id_t *waiting_sa; - enumerator_t *enumerator = initiated->mediated->create_enumerator( - initiated->mediated); - while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) - { - job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, - waiting_sa); - lib->processor->queue_job(lib->processor, job); - } - enumerator->destroy(enumerator); - - this->mutex->unlock(this->mutex); -} - -METHOD(connect_manager_t, set_initiator_data, status_t, - private_connect_manager_t *this, identification_t *initiator, - identification_t *responder, chunk_t connect_id, chunk_t key, - linked_list_t *endpoints, bool is_initiator) -{ - check_list_t *checklist; - - this->mutex->lock(this->mutex); - - if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", - &connect_id); - this->mutex->unlock(this->mutex); - return FAILED; - } - - checklist = check_list_create(initiator, responder, connect_id, key, - endpoints, is_initiator); - this->checklists->insert_last(this->checklists, checklist); - - this->mutex->unlock(this->mutex); - - return SUCCESS; -} - -METHOD(connect_manager_t, set_responder_data, status_t, - private_connect_manager_t *this, chunk_t connect_id, chunk_t key, - linked_list_t *endpoints) -{ - check_list_t *checklist; - - this->mutex->lock(this->mutex); - - if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found", - &connect_id); - this->mutex->unlock(this->mutex); - return NOT_FOUND; - } - - checklist->responder.key = chunk_clone(key); - checklist->responder.endpoints = endpoints->clone_offset(endpoints, - offsetof(endpoint_notify_t, clone)); - checklist->state = CHECK_WAITING; - - build_pairs(checklist); - - /* send the first check immediately */ - schedule_checks(this, checklist, 0); - - this->mutex->unlock(this->mutex); - - return SUCCESS; -} - -METHOD(connect_manager_t, stop_checks, status_t, - private_connect_manager_t *this, chunk_t connect_id) -{ - check_list_t *checklist; - - this->mutex->lock(this->mutex); - - if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) - { - DBG1(DBG_IKE, "checklist with id '%#B' not found", - &connect_id); - this->mutex->unlock(this->mutex); - return NOT_FOUND; - } - - DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id); - - remove_checklist(this, checklist); - check_list_destroy(checklist); - - this->mutex->unlock(this->mutex); - - return SUCCESS; -} - -METHOD(connect_manager_t, destroy, void, - private_connect_manager_t *this) -{ - this->mutex->lock(this->mutex); - - this->checklists->destroy_function(this->checklists, - (void*)check_list_destroy); - this->initiated->destroy_function(this->initiated, - (void*)initiated_destroy); - DESTROY_IF(this->hasher); - - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); - free(this); -} - -/* - * Described in header. - */ -connect_manager_t *connect_manager_create() -{ - private_connect_manager_t *this; - - INIT(this, - .public = { - .destroy = _destroy, - .check_and_register = _check_and_register, - .check_and_initiate = _check_and_initiate, - .set_initiator_data = _set_initiator_data, - .set_responder_data = _set_responder_data, - .process_check = _process_check, - .stop_checks = _stop_checks, - }, - .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .checklists = linked_list_create(), - .initiated = linked_list_create(), - ); - - if (this->hasher == NULL) - { - DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported"); - destroy(this); - return NULL; - } - - return &this->public; -} diff --git a/src/libcharon/sa/connect_manager.h b/src/libcharon/sa/connect_manager.h deleted file mode 100644 index 8fa8ff697..000000000 --- a/src/libcharon/sa/connect_manager.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2007-2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup connect_manager connect_manager - * @{ @ingroup sa - */ - -#ifndef CONNECT_MANAGER_H_ -#define CONNECT_MANAGER_H_ - -typedef struct connect_manager_t connect_manager_t; - -#include -#include -#include - -/** - * The connection manager is responsible for establishing a direct - * connection with another peer. - */ -struct connect_manager_t { - - /** - * Checks if a there is already a mediated connection registered - * between two peers. - * - * @param id my id - * @param peer_id the other peer's id - * @param mediated_sa the IKE_SA ID of the mediated connection - * @returns - * - TRUE, if a mediated connection is registered - * - FALSE, otherwise - */ - bool (*check_and_register) (connect_manager_t *this, identification_t *id, - identification_t *peer_id, - ike_sa_id_t *mediated_sa); - - /** - * Checks if there are waiting connections with a specific peer. - * If so, reinitiate them. - * - * @param id my id - * @param peer_id the other peer's id - */ - void (*check_and_initiate) (connect_manager_t *this, - ike_sa_id_t *mediation_sa, identification_t *id, - identification_t *peer_id); - - /** - * Creates a checklist and sets the initiator's data. - * - * @param initiator ID of the initiator - * @param responder ID of the responder - * @param connect_id the connect ID provided by the initiator - * @param key the initiator's key - * @param endpoints the initiator's endpoints - * @param is_initiator TRUE, if the caller of this method is the initiator - * @returns SUCCESS - */ - status_t (*set_initiator_data) (connect_manager_t *this, - identification_t *initiator, - identification_t *responder, - chunk_t connect_id, chunk_t key, - linked_list_t *endpoints, - bool is_initiator); - - /** - * Updates a checklist and sets the responder's data. The checklist's - * state is advanced to WAITING which means that checks will be sent. - * - * @param connect_id the connect ID - * @param chunk_t the responder's key - * @param endpoints the responder's endpoints - * @returns - * - NOT_FOUND, if the checklist has not been found - * - SUCCESS, otherwise - */ - status_t (*set_responder_data) (connect_manager_t *this, - chunk_t connect_id, chunk_t key, - linked_list_t *endpoints); - - /** - * Stops checks for a checklist. Called after the responder received an - * IKE_SA_INIT request which contains a ME_CONNECTID payload. - * - * @param connect_id the connect ID - * @returns - * - NOT_FOUND, if the checklist has not been found - * - SUCCESS, otherwise - */ - status_t (*stop_checks) (connect_manager_t *this, chunk_t connect_id); - - /** - * Processes a connectivity check - * - * @param message the received message - */ - void (*process_check) (connect_manager_t *this, message_t *message); - - /** - * Destroys the manager with all data. - */ - void (*destroy) (connect_manager_t *this); -}; - -/** - * Create a manager. - * - * @returns connect_manager_t object - */ -connect_manager_t *connect_manager_create(void); - -#endif /** CONNECT_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c new file mode 100644 index 000000000..520c0ce56 --- /dev/null +++ b/src/libcharon/sa/eap/eap_manager.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_manager.h" + +#include +#include + +typedef struct private_eap_manager_t private_eap_manager_t; +typedef struct eap_entry_t eap_entry_t; + +/** + * EAP constructor entry + */ +struct eap_entry_t { + + /** + * EAP method type, vendor specific if vendor is set + */ + eap_type_t type; + + /** + * vendor ID, 0 for default EAP methods + */ + u_int32_t vendor; + + /** + * Role of the method returned by the constructor, EAP_SERVER or EAP_PEER + */ + eap_role_t role; + + /** + * constructor function to create instance + */ + eap_constructor_t constructor; +}; + +/** + * private data of eap_manager + */ +struct private_eap_manager_t { + + /** + * public functions + */ + eap_manager_t public; + + /** + * list of eap_entry_t's + */ + linked_list_t *methods; + + /** + * rwlock to lock methods + */ + rwlock_t *lock; +}; + +METHOD(eap_manager_t, add_method, void, + private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, eap_constructor_t constructor) +{ + eap_entry_t *entry = malloc_thing(eap_entry_t); + + entry->type = type; + entry->vendor = vendor; + entry->role = role; + entry->constructor = constructor; + + this->lock->write_lock(this->lock); + this->methods->insert_last(this->methods, entry); + this->lock->unlock(this->lock); +} + +METHOD(eap_manager_t, remove_method, void, + private_eap_manager_t *this, eap_constructor_t constructor) +{ + enumerator_t *enumerator; + eap_entry_t *entry; + + this->lock->write_lock(this->lock); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (constructor == entry->constructor) + { + this->methods->remove_at(this->methods, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +/** + * filter the registered methods + */ +static bool filter_methods(uintptr_t role, eap_entry_t **entry, + eap_type_t *type, void *in, u_int32_t *vendor) +{ + if ((*entry)->role != (eap_role_t)role) + { + return FALSE; + } + if ((*entry)->vendor == 0 && + ((*entry)->type < 4 || (*entry)->type == EAP_EXPANDED || + (*entry)->type > EAP_EXPERIMENTAL)) + { /* filter invalid types */ + return FALSE; + } + if (type) + { + *type = (*entry)->type; + } + if (vendor) + { + *vendor = (*entry)->vendor; + } + return TRUE; +} + +METHOD(eap_manager_t, create_enumerator, enumerator_t*, + private_eap_manager_t *this, eap_role_t role) +{ + this->lock->read_lock(this->lock); + return enumerator_create_cleaner( + enumerator_create_filter( + this->methods->create_enumerator(this->methods), + (void*)filter_methods, (void*)(uintptr_t)role, NULL), + (void*)this->lock->unlock, this->lock); +} + +METHOD(eap_manager_t, create_instance, eap_method_t*, + private_eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, identification_t *server, identification_t *peer) +{ + enumerator_t *enumerator; + eap_entry_t *entry; + eap_method_t *method = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (type == entry->type && vendor == entry->vendor && + role == entry->role) + { + method = entry->constructor(server, peer); + if (method) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return method; +} + +METHOD(eap_manager_t, destroy, void, + private_eap_manager_t *this) +{ + this->methods->destroy_function(this->methods, free); + this->lock->destroy(this->lock); + free(this); +} + +/* + * See header + */ +eap_manager_t *eap_manager_create() +{ + private_eap_manager_t *this; + + INIT(this, + .public = { + .add_method = _add_method, + .remove_method = _remove_method, + .create_enumerator = _create_enumerator, + .create_instance = _create_instance, + .destroy = _destroy, + }, + .methods = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/eap/eap_manager.h b/src/libcharon/sa/eap/eap_manager.h new file mode 100644 index 000000000..e318ef57a --- /dev/null +++ b/src/libcharon/sa/eap/eap_manager.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_manager eap_manager + * @{ @ingroup eap + */ + +#ifndef EAP_MANAGER_H_ +#define EAP_MANAGER_H_ + +#include + +typedef struct eap_manager_t eap_manager_t; + +/** + * The EAP manager manages all EAP implementations and creates instances. + * + * A plugin registers it's implemented EAP method at the manager by + * providing type and a contructor function. The manager then instanciates + * eap_method_t instances through the provided constructor to handle + * EAP authentication. + */ +struct eap_manager_t { + + /** + * Register a EAP method implementation. + * + * @param method vendor specific method, if vendor != 0 + * @param vendor vendor ID, 0 for non-vendor (default) EAP methods + * @param role EAP role of the registered method + * @param constructor constructor function, returns an eap_method_t + */ + void (*add_method)(eap_manager_t *this, eap_type_t type, u_int32_t vendor, + eap_role_t role, eap_constructor_t constructor); + + /** + * Unregister a EAP method implementation using it's constructor. + * + * @param constructor constructor function to remove, as added in add_method + */ + void (*remove_method)(eap_manager_t *this, eap_constructor_t constructor); + + /** + * Enumerate the registered EAP authentication methods for the given role. + * + * @note Only authentication types are enumerated (e.g. EAP-Identity is not + * even though it is registered as method with this manager). + * + * @param role EAP role of methods to enumerate + * @return enumerator over (eap_type_t type, u_int32_t vendor) + */ + enumerator_t* (*create_enumerator)(eap_manager_t *this, eap_role_t role); + + /** + * Create a new EAP method instance. + * + * @param type type of the EAP method + * @param vendor vendor ID, 0 for non-vendor (default) EAP methods + * @param role role of EAP method, either EAP_SERVER or EAP_PEER + * @param server identity of the server + * @param peer identity of the peer (client) + * @return EAP method instance, NULL if no constructor found + */ + eap_method_t* (*create_instance)(eap_manager_t *this, eap_type_t type, + u_int32_t vendor, eap_role_t role, + identification_t *server, + identification_t *peer); + + /** + * Destroy a eap_manager instance. + */ + void (*destroy)(eap_manager_t *this); +}; + +/** + * Create a eap_manager instance. + */ +eap_manager_t *eap_manager_create(); + +#endif /** EAP_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/eap/eap_method.c b/src/libcharon/sa/eap/eap_method.c new file mode 100644 index 000000000..a05e8c59a --- /dev/null +++ b/src/libcharon/sa/eap/eap_method.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_method.h" + +#include + +ENUM(eap_role_names, EAP_SERVER, EAP_PEER, + "EAP_SERVER", + "EAP_PEER", +); + +/** + * See header + */ +bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data) +{ + if (reg) + { + charon->eap->add_method(charon->eap, feature->arg.eap, 0, + feature->type == FEATURE_EAP_SERVER ? EAP_SERVER : EAP_PEER, + (eap_constructor_t)data); + } + else + { + charon->eap->remove_method(charon->eap, (eap_constructor_t)data); + } + return TRUE; +} diff --git a/src/libcharon/sa/eap/eap_method.h b/src/libcharon/sa/eap/eap_method.h new file mode 100644 index 000000000..6242a5a6e --- /dev/null +++ b/src/libcharon/sa/eap/eap_method.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_method eap_method + * @{ @ingroup eap + */ + +#ifndef EAP_METHOD_H_ +#define EAP_METHOD_H_ + +typedef struct eap_method_t eap_method_t; +typedef enum eap_role_t eap_role_t; + +#include +#include +#include +#include +#include + +/** + * Role of an eap_method, SERVER or PEER (client) + */ +enum eap_role_t { + EAP_SERVER, + EAP_PEER, +}; +/** + * enum names for eap_role_t. + */ +extern enum_name_t *eap_role_names; + +/** + * Interface of an EAP method for server and client side. + * + * An EAP method initiates an EAP exchange and processes requests and + * responses. An EAP method may need multiple exchanges before succeeding, and + * the eap_authentication may use multiple EAP methods to authenticate a peer. + * To accomplish these requirements, all EAP methods have their own + * implementation while the eap_authenticatior uses one or more of these + * EAP methods. Sending of EAP(SUCCESS/FAILURE) message is not the job + * of the method, the eap_authenticator does this. + * An EAP method may establish a MSK, this is used the complete the + * authentication. Even if a mutual EAP method is used, the traditional + * AUTH payloads are required. Only these include the nonces and messages from + * ike_sa_init and therefore prevent man in the middle attacks. + * The EAP method must use an initial EAP identifier value != 0, as a preceding + * EAP-Identity exchange always uses identifier 0. + */ +struct eap_method_t { + + /** + * Initiate the EAP exchange. + * + * initiate() is only useable for server implementations, as clients only + * reply to server requests. + * A eap_payload is created in "out" if result is NEED_MORE. + * + * @param out eap_payload to send to the client + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if unable to create eap request payload + */ + status_t (*initiate) (eap_method_t *this, eap_payload_t **out); + + /** + * Process a received EAP message. + * + * A eap_payload is created in "out" if result is NEED_MORE. + * + * @param in eap_payload response received + * @param out created eap_payload to send + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if EAP method failed + * - SUCCESS, if EAP method succeeded + */ + status_t (*process) (eap_method_t *this, eap_payload_t *in, + eap_payload_t **out); + + /** + * Get the EAP type implemented in this method. + * + * @param vendor pointer receiving vendor identifier for type, 0 for none + * @return type of the EAP method + */ + eap_type_t (*get_type) (eap_method_t *this, u_int32_t *vendor); + + /** + * Check if this EAP method authenticates the server. + * + * Some EAP methods provide mutual authentication and + * allow authentication using only EAP, if the peer supports it. + * + * @return TRUE if methods provides mutual authentication + */ + bool (*is_mutual) (eap_method_t *this); + + /** + * Get the MSK established by this EAP method. + * + * Not all EAP methods establish a shared secret. For implementations of + * the EAP-Identity method, get_msk() returns the received identity. + * + * @param msk chunk receiving internal stored MSK + * @return + * - SUCCESS, or + * - FAILED, if MSK not established (yet) + */ + status_t (*get_msk) (eap_method_t *this, chunk_t *msk); + + /** + * Get the current EAP identifier. + * + * @return current EAP identifier + */ + u_int8_t (*get_identifier) (eap_method_t *this); + + /** + * Set the EAP identifier to a deterministic value, overwriting + * the randomly initialized default value. + * + * @param identifier current EAP identifier + */ + void (*set_identifier) (eap_method_t *this, u_int8_t identifier); + + /** + * Destroys a eap_method_t object. + */ + void (*destroy) (eap_method_t *this); +}; + +/** + * Constructor definition for a pluggable EAP method. + * + * Each EAP module must define a constructor function which will return + * an initialized object with the methods defined in eap_method_t. + * Constructors for server and peers are identical, to support both roles + * of a EAP method, a plugin needs register two constructors in the + * eap_manager_t. + * The passed identites are of type ID_EAP and valid only during the + * constructor invocation. + * + * @param server ID of the server to use for credential lookup + * @param peer ID of the peer to use for credential lookup + * @return implementation of the eap_method_t interface + */ +typedef eap_method_t *(*eap_constructor_t)(identification_t *server, + identification_t *peer); + +/** + * Helper function to (un-)register EAP methods from plugin features. + * + * This function is a plugin_feature_callback_t and can be used with the + * PLUGIN_CALLBACK macro to register a EAP method constructor. + * + * @param plugin plugin registering the EAP method constructor + * @param feature associated plugin feature + * @param reg TRUE to register, FALSE to unregister. + * @param data data passed to callback, an eap_constructor_t + */ +bool eap_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data); + +#endif /** EAP_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 07d19381d..1d49acb52 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,32 +28,16 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include -#include +#include +#include #ifdef ME -#include +#include #include #endif @@ -85,6 +69,11 @@ struct private_ike_sa_t { */ ike_sa_id_t *ike_sa_id; + /** + * IKE version of this SA. + */ + ike_version_t version; + /** * unique numerical ID for this IKE_SA. */ @@ -193,14 +182,14 @@ struct private_ike_sa_t { keymat_t *keymat; /** - * Virtual IP on local host, if any + * Virtual IPs on local host */ - host_t *my_virtual_ip; + linked_list_t *my_vips; /** - * Virtual IP on remote host, if any + * Virtual IPs on remote host */ - host_t *other_virtual_ip; + linked_list_t *other_vips; /** * List of configuration attributes (attribute_entry_t) @@ -227,6 +216,17 @@ struct private_ike_sa_t { */ u_int32_t keepalive_interval; + /** + * interval for retries during initiation (e.g. if DNS resolution failed), + * 0 to disable (default) + */ + u_int32_t retry_initiate_interval; + + /** + * TRUE if a retry_initiate_job has been queued + */ + bool retry_initiate_queued; + /** * Timestamps for this IKE_SA */ @@ -248,9 +248,9 @@ struct private_ike_sa_t { host_t *remote_host; /** - * TRUE if we are currently reauthenticating this IKE_SA + * Flush auth configs once established? */ - bool is_reauthenticating; + bool flush_auth_cfg; }; /** @@ -319,6 +319,15 @@ METHOD(ike_sa_t, get_statistic, u_int32_t, return 0; } +METHOD(ike_sa_t, set_statistic, void, + private_ike_sa_t *this, statistic_t kind, u_int32_t value) +{ + if (kind < STAT_MAX) + { + this->stats[kind] = value; + } +} + METHOD(ike_sa_t, get_my_host, host_t*, private_ike_sa_t *this) { @@ -405,6 +414,9 @@ static void flush_auth_cfgs(private_ike_sa_t *this) { auth_cfg_t *cfg; + this->my_auth->purge(this->my_auth, FALSE); + this->other_auth->purge(this->other_auth, FALSE); + while (this->my_auths->remove_last(this->my_auths, (void**)&cfg) == SUCCESS) { @@ -471,8 +483,8 @@ METHOD(ike_sa_t, send_keepalive, void, data.ptr[0] = 0xFF; data.len = 1; packet->set_data(packet, data); - DBG1(DBG_IKE, "sending keep alive"); - charon->sender->send(charon->sender, packet); + DBG1(DBG_IKE, "sending keep alive to %#H", this->other_host); + charon->sender->send_no_marker(charon->sender, packet); diff = 0; } job = send_keepalive_job_create(this->ike_sa_id); @@ -563,6 +575,7 @@ METHOD(ike_sa_t, send_dpd, status_t, { job_t *job; time_t diff, delay; + bool task_queued = FALSE; if (this->state == IKE_PASSIVE) { @@ -583,27 +596,11 @@ METHOD(ike_sa_t, send_dpd, status_t, diff = now - last_in; if (!delay || diff >= delay) { - /* to long ago, initiate dead peer detection */ - task_t *task; - ike_mobike_t *mobike; - - if (supports_extension(this, EXT_MOBIKE) && - has_condition(this, COND_NAT_HERE)) - { - /* use mobike enabled DPD to detect NAT mapping changes */ - mobike = ike_mobike_create(&this->public, TRUE); - mobike->dpd(mobike); - task = &mobike->task; - } - else - { - task = (task_t*)ike_dpd_create(TRUE); - } - diff = 0; + /* too long ago, initiate dead peer detection */ DBG1(DBG_IKE, "sending DPD request"); - - this->task_manager->queue_task(this->task_manager, task); - this->task_manager->initiate(this->task_manager); + this->task_manager->queue_dpd(this->task_manager); + task_queued = TRUE; + diff = 0; } } /* recheck in "interval" seconds */ @@ -612,6 +609,10 @@ METHOD(ike_sa_t, send_dpd, status_t, job = (job_t*)send_dpd_job_create(this->ike_sa_id); lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); } + if (task_queued) + { + return this->task_manager->initiate(this->task_manager); + } return SUCCESS; } @@ -646,7 +647,7 @@ METHOD(ike_sa_t, set_state, void, /* schedule rekeying if we have a time which is smaller than * an already scheduled rekeying */ - t = this->peer_cfg->get_rekey_time(this->peer_cfg); + t = this->peer_cfg->get_rekey_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REKEY] == 0 || (this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED]))) { @@ -655,7 +656,7 @@ METHOD(ike_sa_t, set_state, void, lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } - t = this->peer_cfg->get_reauth_time(this->peer_cfg); + t = this->peer_cfg->get_reauth_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REAUTH] == 0 || (this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED]))) { @@ -698,7 +699,14 @@ METHOD(ike_sa_t, set_state, void, if (trigger_dpd) { - send_dpd(this); + if (supports_extension(this, EXT_DPD)) + { + send_dpd(this); + } + else + { + DBG1(DBG_IKE, "DPD not supported by peer, disabled"); + } } } @@ -716,7 +724,8 @@ METHOD(ike_sa_t, reset, void, flush_auth_cfgs(this); this->keymat->destroy(this->keymat); - this->keymat = keymat_create(this->ike_sa_id->is_initiator(this->ike_sa_id)); + this->keymat = keymat_create(this->version, + this->ike_sa_id->is_initiator(this->ike_sa_id)); this->task_manager->reset(this->task_manager, 0, 0); } @@ -727,7 +736,7 @@ METHOD(ike_sa_t, get_keymat, keymat_t*, return this->keymat; } -METHOD(ike_sa_t, set_virtual_ip, void, +METHOD(ike_sa_t, add_virtual_ip, void, private_ike_sa_t *this, bool local, host_t *ip) { if (local) @@ -736,39 +745,44 @@ METHOD(ike_sa_t, set_virtual_ip, void, if (hydra->kernel_interface->add_ip(hydra->kernel_interface, ip, this->my_host) == SUCCESS) { - if (this->my_virtual_ip) - { - DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip); - hydra->kernel_interface->del_ip(hydra->kernel_interface, - this->my_virtual_ip); - } - DESTROY_IF(this->my_virtual_ip); - this->my_virtual_ip = ip->clone(ip); + this->my_vips->insert_last(this->my_vips, ip->clone(ip)); } else { DBG1(DBG_IKE, "installing virtual IP %H failed", ip); - this->my_virtual_ip = NULL; } } else { - DESTROY_IF(this->other_virtual_ip); - this->other_virtual_ip = ip->clone(ip); + this->other_vips->insert_last(this->other_vips, ip->clone(ip)); } } -METHOD(ike_sa_t, get_virtual_ip, host_t*, + +METHOD(ike_sa_t, clear_virtual_ips, void, private_ike_sa_t *this, bool local) { - if (local) + linked_list_t *vips = local ? this->my_vips : this->other_vips; + host_t *vip; + + while (vips->remove_first(vips, (void**)&vip) == SUCCESS) { - return this->my_virtual_ip; + if (local) + { + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + } + vip->destroy(vip); } - else +} + +METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*, + private_ike_sa_t *this, bool local) +{ + if (local) { - return this->other_virtual_ip; + return this->my_vips->create_enumerator(this->my_vips); } + return this->other_vips->create_enumerator(this->other_vips); } METHOD(ike_sa_t, add_peer_address, void, @@ -837,9 +851,11 @@ METHOD(ike_sa_t, float_ports, void, private_ike_sa_t *this) { /* do not switch if we have a custom port from MOBIKE/NAT */ - if (this->my_host->get_port(this->my_host) == IKEV2_UDP_PORT) + if (this->my_host->get_port(this->my_host) == + charon->socket->get_port(charon->socket, FALSE)) { - this->my_host->set_port(this->my_host, IKEV2_NATT_PORT); + this->my_host->set_port(this->my_host, + charon->socket->get_port(charon->socket, TRUE)); } if (this->other_host->get_port(this->other_host) == IKEV2_UDP_PORT) { @@ -899,7 +915,7 @@ METHOD(ike_sa_t, update_hosts, void, while (enumerator->enumerate(enumerator, (void**)&child_sa)) { if (child_sa->update(child_sa, this->my_host, - this->other_host, this->my_virtual_ip, + this->other_host, this->my_vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED) { this->public.rekey_child_sa(&this->public, @@ -914,6 +930,8 @@ METHOD(ike_sa_t, update_hosts, void, METHOD(ike_sa_t, generate_message, status_t, private_ike_sa_t *this, message_t *message, packet_t **packet) { + status_t status; + if (message->is_encoded(message)) { /* already done */ *packet = message->get_packet(message); @@ -921,44 +939,13 @@ METHOD(ike_sa_t, generate_message, status_t, } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); - charon->bus->message(charon->bus, message, FALSE); - return message->generate(message, - this->keymat->get_aead(this->keymat, FALSE), packet); -} - -/** - * send a notify back to the sender - */ -static void send_notify_response(private_ike_sa_t *this, message_t *request, - notify_type_t type, chunk_t data) -{ - message_t *response; - packet_t *packet; - - response = message_create(); - response->set_exchange_type(response, request->get_exchange_type(request)); - response->set_request(response, FALSE); - response->set_message_id(response, request->get_message_id(request)); - response->add_notify(response, FALSE, type, data); - if (this->my_host->is_anyaddr(this->my_host)) - { - this->my_host->destroy(this->my_host); - this->my_host = request->get_destination(request); - this->my_host = this->my_host->clone(this->my_host); - } - if (this->other_host->is_anyaddr(this->other_host)) - { - this->other_host->destroy(this->other_host); - this->other_host = request->get_source(request); - this->other_host = this->other_host->clone(this->other_host); - } - response->set_source(response, this->my_host->clone(this->my_host)); - response->set_destination(response, this->other_host->clone(this->other_host)); - if (generate_message(this, response, &packet) == SUCCESS) + charon->bus->message(charon->bus, message, FALSE, TRUE); + status = message->generate(message, this->keymat, packet); + if (status == SUCCESS) { - charon->sender->send(charon->sender, packet); + charon->bus->message(charon->bus, message, FALSE, FALSE); } - response->destroy(response); + return status; } METHOD(ike_sa_t, set_kmaddress, void, @@ -1060,8 +1047,12 @@ static void resolve_hosts(private_ike_sa_t *this) } else { - host = host_create_from_dns(this->ike_cfg->get_other_addr(this->ike_cfg), - 0, this->ike_cfg->get_other_port(this->ike_cfg)); + char *other_addr; + u_int16_t other_port; + + other_addr = this->ike_cfg->get_other_addr(this->ike_cfg, NULL); + other_port = this->ike_cfg->get_other_port(this->ike_cfg); + host = host_create_from_dns(other_addr, 0, other_port); } if (host) { @@ -1071,10 +1062,12 @@ static void resolve_hosts(private_ike_sa_t *this) if (this->local_host) { host = this->local_host->clone(this->local_host); - host->set_port(host, IKEV2_UDP_PORT); + host->set_port(host, charon->socket->get_port(charon->socket, FALSE)); } else { + char *my_addr; + u_int16_t my_port; int family = 0; /* use same address family as for other */ @@ -1082,8 +1075,9 @@ static void resolve_hosts(private_ike_sa_t *this) { family = this->other_host->get_family(this->other_host); } - host = host_create_from_dns(this->ike_cfg->get_my_addr(this->ike_cfg), - family, this->ike_cfg->get_my_port(this->ike_cfg)); + my_addr = this->ike_cfg->get_my_addr(this->ike_cfg, NULL); + my_port = this->ike_cfg->get_my_port(this->ike_cfg); + host = host_create_from_dns(my_addr, family, my_port); if (host && host->is_anyaddr(host) && !this->other_host->is_anyaddr(this->other_host)) @@ -1097,9 +1091,7 @@ static void resolve_hosts(private_ike_sa_t *this) } else { /* fallback to address family specific %any(6), if configured */ - host = host_create_from_dns( - this->ike_cfg->get_my_addr(this->ike_cfg), - 0, this->ike_cfg->get_my_port(this->ike_cfg)); + host = host_create_from_dns(my_addr, 0, my_port); } } } @@ -1113,7 +1105,7 @@ METHOD(ike_sa_t, initiate, status_t, private_ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) { - task_t *task; + bool defer_initiate = FALSE; if (this->state == IKE_CREATED) { @@ -1129,39 +1121,31 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ ) { - child_cfg->destroy(child_cfg); - DBG1(DBG_IKE, "unable to initiate to %%any"); - charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED); - return DESTROY_ME; + char *addr = this->ike_cfg->get_other_addr(this->ike_cfg, NULL); + bool is_anyaddr = streq(addr, "%any") || streq(addr, "%any6"); + + if (is_anyaddr || !this->retry_initiate_interval) + { + if (is_anyaddr) + { + DBG1(DBG_IKE, "unable to initiate to %s", addr); + } + else + { + DBG1(DBG_IKE, "unable to resolve %s, initiate aborted", + addr); + } + DESTROY_IF(child_cfg); + charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED); + return DESTROY_ME; + } + DBG1(DBG_IKE, "unable to resolve %s, retrying in %ds", + addr, this->retry_initiate_interval); + defer_initiate = TRUE; } set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); - - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_pre_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_post_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_config_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - if (this->peer_cfg->use_mobike(this->peer_cfg)) - { - task = (task_t*)ike_mobike_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - } -#ifdef ME - task = (task_t*)ike_me_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); -#endif /* ME */ + this->task_manager->queue_ike(this->task_manager); } #ifdef ME @@ -1178,18 +1162,11 @@ METHOD(ike_sa_t, initiate, status_t, } else #endif /* ME */ + if (child_cfg) { /* normal IKE_SA with CHILD_SA */ - task = (task_t*)child_create_create(&this->public, child_cfg, FALSE, - tsi, tsr); - child_cfg->destroy(child_cfg); - if (reqid) - { - child_create_t *child_create = (child_create_t*)task; - child_create->use_reqid(child_create, reqid); - } - this->task_manager->queue_task(this->task_manager, task); - + this->task_manager->queue_child(this->task_manager, child_cfg, reqid, + tsi, tsr); #ifdef ME if (this->peer_cfg->get_mediated_by(this->peer_cfg)) { @@ -1201,135 +1178,74 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ } + if (defer_initiate) + { + if (!this->retry_initiate_queued) + { + job_t *job = (job_t*)retry_initiate_job_create(this->ike_sa_id); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, + this->retry_initiate_interval); + this->retry_initiate_queued = TRUE; + } + return SUCCESS; + } + this->retry_initiate_queued = FALSE; return this->task_manager->initiate(this->task_manager); } +METHOD(ike_sa_t, retry_initiate, status_t, + private_ike_sa_t *this) +{ + if (this->retry_initiate_queued) + { + this->retry_initiate_queued = FALSE; + return initiate(this, NULL, 0, NULL, NULL); + } + return SUCCESS; +} + METHOD(ike_sa_t, process_message, status_t, private_ike_sa_t *this, message_t *message) { status_t status; - bool is_request; - u_int8_t type = 0; if (this->state == IKE_PASSIVE) { /* do not handle messages in passive state */ return FAILED; } - - is_request = message->get_request(message); - - status = message->parse_body(message, - this->keymat->get_aead(this->keymat, TRUE)); - if (status == SUCCESS) - { /* check for unsupported critical payloads */ - enumerator_t *enumerator; - unknown_payload_t *unknown; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - unknown = (unknown_payload_t*)payload; - type = payload->get_type(payload); - if (!payload_is_known(type) && - unknown->is_critical(unknown)) + switch (message->get_exchange_type(message)) + { + case ID_PROT: + case AGGRESSIVE: + case IKE_SA_INIT: + case IKE_AUTH: + if (this->state != IKE_CREATED && + this->state != IKE_CONNECTING) { - DBG1(DBG_ENC, "payload type %N is not supported, " - "but its critical!", payload_type_names, type); - status = NOT_SUPPORTED; + DBG1(DBG_IKE, "ignoring %N in established IKE_SA state", + exchange_type_names, message->get_exchange_type(message)); + return FAILED; } - } - enumerator->destroy(enumerator); + break; + default: + break; } - if (status != SUCCESS) + if (message->get_major_version(message) != this->version) { - if (is_request) - { - switch (status) - { - case NOT_SUPPORTED: - DBG1(DBG_IKE, "critical unknown payloads found"); - if (is_request) - { - send_notify_response(this, message, - UNSUPPORTED_CRITICAL_PAYLOAD, - chunk_from_thing(type)); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - default: - break; - } - } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA", exchange_type_names, message->get_exchange_type(message), - message->get_request(message) ? "request" : "response", - message->get_message_id(message)); - - if (this->state == IKE_CREATED) - { /* invalid initiation attempt, close SA */ - return DESTROY_ME; - } + message->get_major_version(message), + ike_version_names, this->version); + /* TODO-IKEv1: fall back to IKEv1 if we receive an IKEv1 + * INVALID_MAJOR_VERSION on an IKEv2 SA. */ + return FAILED; } - else + status = this->task_manager->process_message(this->task_manager, message); + if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED) { - /* if this IKE_SA is virgin, we check for a config */ - if (this->ike_cfg == NULL) - { - job_t *job; - host_t *me = message->get_destination(message), - *other = message->get_source(message); - this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, - me, other); - if (this->ike_cfg == NULL) - { - /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", - me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, message, - NO_PROPOSAL_CHOSEN, chunk_empty); - return DESTROY_ME; - } - /* add a timeout if peer does not establish it completely */ - job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - lib->scheduler->schedule_job(lib->scheduler, job, - lib->settings->get_int(lib->settings, - "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); - } - this->stats[STAT_INBOUND] = time_monotonic(NULL); - status = this->task_manager->process_message(this->task_manager, - message); - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED && - lib->settings->get_bool(lib->settings, - "charon.flush_auth_cfg", FALSE)) - { /* authentication completed */ - flush_auth_cfgs(this); - } + /* authentication completed */ + this->flush_auth_cfg = FALSE; + flush_auth_cfgs(this); } return status; } @@ -1340,6 +1256,12 @@ METHOD(ike_sa_t, get_id, ike_sa_id_t*, return this->ike_sa_id; } +METHOD(ike_sa_t, get_version, ike_version_t, + private_ike_sa_t *this) +{ + return this->version; +} + METHOD(ike_sa_t, get_my_id, identification_t*, private_ike_sa_t *this) { @@ -1372,6 +1294,10 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*, /* prefer EAP-Identity of last round */ current = cfg->get(cfg, AUTH_RULE_EAP_IDENTITY); if (!current || current->get_type(current) == ID_ANY) + { + current = cfg->get(cfg, AUTH_RULE_XAUTH_IDENTITY); + } + if (!current || current->get_type(current) == ID_ANY) { current = cfg->get(cfg, AUTH_RULE_IDENTITY); } @@ -1442,30 +1368,23 @@ METHOD(ike_sa_t, remove_child_sa, void, METHOD(ike_sa_t, rekey_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - child_rekey_t *child_rekey; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - - child_rekey = child_rekey_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_rekey->task); + this->task_manager->queue_child_rekey(this->task_manager, protocol, spi); return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, delete_child_sa, status_t, - private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) + private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool expired) { - child_delete_t *child_delete; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - - child_delete = child_delete_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_delete->task); + this->task_manager->queue_child_delete(this->task_manager, + protocol, spi, expired); return this->task_manager->initiate(this->task_manager); } @@ -1495,14 +1414,17 @@ METHOD(ike_sa_t, destroy_child_sa, status_t, METHOD(ike_sa_t, delete_, status_t, private_ike_sa_t *this) { - ike_delete_t *ike_delete; - switch (this->state) { - case IKE_ESTABLISHED: case IKE_REKEYING: - ike_delete = ike_delete_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, &ike_delete->task); + if (this->version == IKEV1) + { /* SA has been reauthenticated, delete */ + charon->bus->ike_updown(charon->bus, &this->public, FALSE); + break; + } + /* FALL */ + case IKE_ESTABLISHED: + this->task_manager->queue_ike_delete(this->task_manager); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: DBG1(DBG_IKE, "deleting unestablished IKE_SA"); @@ -1521,23 +1443,17 @@ METHOD(ike_sa_t, delete_, status_t, METHOD(ike_sa_t, rekey, status_t, private_ike_sa_t *this) { - ike_rekey_t *ike_rekey; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; } - ike_rekey = ike_rekey_create(&this->public, TRUE); - - this->task_manager->queue_task(this->task_manager, &ike_rekey->task); + this->task_manager->queue_ike_rekey(this->task_manager); return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, reauth, status_t, private_ike_sa_t *this) { - task_t *task; - if (this->state == IKE_PASSIVE) { return INVALID_STATE; @@ -1548,7 +1464,8 @@ METHOD(ike_sa_t, reauth, status_t, if (!has_condition(this, COND_ORIGINAL_INITIATOR)) { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); - if (this->other_virtual_ip != NULL || + if (this->other_vips->get_count(this->other_vips) != 0 || + has_condition(this, COND_XAUTH_AUTHENTICATED) || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME /* as mediation server we too cannot reauth the IKE_SA */ @@ -1575,10 +1492,8 @@ METHOD(ike_sa_t, reauth, status_t, DBG0(DBG_IKE, "reauthenticating IKE_SA %s[%d]", get_name(this), this->unique_id); } - this->is_reauthenticating = TRUE; - task = (task_t*)ike_reauth_create(&this->public); - this->task_manager->queue_task(this->task_manager, task); - + set_condition(this, COND_REAUTHENTICATING, TRUE); + this->task_manager->queue_ike_reauth(this->task_manager); return this->task_manager->initiate(this->task_manager); } @@ -1594,7 +1509,7 @@ METHOD(ike_sa_t, reestablish, status_t, bool restart = FALSE; status_t status = FAILED; - if (this->is_reauthenticating) + if (has_condition(this, COND_REAUTHENTICATING)) { /* only reauthenticate if we have children */ if (this->child_sas->get_count(this->child_sas) == 0 #ifdef ME @@ -1653,7 +1568,7 @@ METHOD(ike_sa_t, reestablish, status_t, /* check if we are able to reestablish this IKE_SA */ if (!has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_virtual_ip != NULL || + (this->other_vips->get_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME || this->is_mediation_server @@ -1664,18 +1579,24 @@ METHOD(ike_sa_t, reestablish, status_t, return FAILED; } - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->version, TRUE); + if (!new) + { + return FAILED; + } new->set_peer_cfg(new, this->peer_cfg); host = this->other_host; new->set_other_host(new, host->clone(host)); host = this->my_host; new->set_my_host(new, host->clone(host)); /* if we already have a virtual IP, we reuse it */ - host = this->my_virtual_ip; - if (host) + enumerator = this->my_vips->create_enumerator(this->my_vips); + while (enumerator->enumerate(enumerator, &host)) { - new->set_virtual_ip(new, TRUE, host); + new->add_virtual_ip(new, TRUE, host); } + enumerator->destroy(enumerator); #ifdef ME if (this->peer_cfg->is_mediation(this->peer_cfg)) @@ -1688,7 +1609,7 @@ METHOD(ike_sa_t, reestablish, status_t, enumerator = this->child_sas->create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { - if (this->is_reauthenticating) + if (has_condition(this, COND_REAUTHENTICATING)) { switch (child_sa->get_state(child_sa)) { @@ -1744,6 +1665,7 @@ METHOD(ike_sa_t, reestablish, status_t, } else { + charon->bus->ike_reestablish(charon->bus, &this->public, new); charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); status = SUCCESS; } @@ -1751,40 +1673,6 @@ METHOD(ike_sa_t, reestablish, status_t, return status; } -/** - * Requeue the IKE_SA_INIT tasks for initiation, if required - */ -static void requeue_init_tasks(private_ike_sa_t *this) -{ - enumerator_t *enumerator; - bool has_init = FALSE; - task_t *task; - - /* if we have advanced to IKE_AUTH, the IKE_INIT and related tasks - * have already completed. Recreate them if necessary. */ - enumerator = this->task_manager->create_task_enumerator( - this->task_manager, TASK_QUEUE_QUEUED); - while (enumerator->enumerate(enumerator, &task)) - { - if (task->get_type(task) == IKE_INIT) - { - has_init = TRUE; - break; - } - } - enumerator->destroy(enumerator); - - if (!has_init) - { - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - } -} - METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { @@ -1800,7 +1688,7 @@ METHOD(ike_sa_t, retransmit, status_t, { case IKE_CONNECTING: { - /* retry IKE_SA_INIT if we have multiple keyingtries */ + /* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */ u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg); this->keyingtry++; if (tries == 0 || tries > this->keyingtry) @@ -1809,7 +1697,7 @@ METHOD(ike_sa_t, retransmit, status_t, this->keyingtry + 1, tries); reset(this); resolve_hosts(this); - requeue_init_tasks(this); + this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); @@ -1817,7 +1705,7 @@ METHOD(ike_sa_t, retransmit, status_t, } case IKE_DELETING: DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding"); - if (this->is_reauthenticating) + if (has_condition(this, COND_REAUTHENTICATING)) { DBG1(DBG_IKE, "delete during reauthentication failed, " "trying to reestablish IKE_SA anyway"); @@ -1831,6 +1719,10 @@ METHOD(ike_sa_t, retransmit, status_t, reestablish(this); break; } + if (this->state != IKE_CONNECTING) + { + charon->bus->ike_updown(charon->bus, &this->public, FALSE); + } return DESTROY_ME; } return SUCCESS; @@ -1840,7 +1732,6 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, private_ike_sa_t *this, u_int32_t lifetime) { u_int32_t diff, hard, soft, now; - ike_auth_lifetime_t *task; bool send_update; diff = this->peer_cfg->get_over_time(this->peer_cfg); @@ -1850,9 +1741,9 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, /* check if we have to send an AUTH_LIFETIME to enforce the new lifetime. * We send the notify in IKE_AUTH if not yet ESTABLISHED. */ - send_update = this->state == IKE_ESTABLISHED && + send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 && !has_condition(this, COND_ORIGINAL_INITIATOR) && - (this->other_virtual_ip != NULL || + (this->other_vips->get_count(this->other_vips) != 0 || has_condition(this, COND_EAP_AUTHENTICATED)); if (lifetime < diff) @@ -1890,12 +1781,16 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t, /* give at least some seconds to reauthenticate */ this->stats[STAT_DELETE] = max(hard, now + 10); +#ifdef USE_IKEV2 if (send_update) { + ike_auth_lifetime_t *task; + task = ike_auth_lifetime_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, &task->task); return this->task_manager->initiate(this->task_manager); } +#endif return SUCCESS; } @@ -1953,8 +1848,6 @@ static bool is_any_path_valid(private_ike_sa_t *this) METHOD(ike_sa_t, roam, status_t, private_ike_sa_t *this, bool address) { - ike_mobike_t *mobike; - switch (this->state) { case IKE_CREATED: @@ -1976,10 +1869,7 @@ METHOD(ike_sa_t, roam, status_t, if (supports_extension(this, EXT_MOBIKE) && address) { /* if any addresses changed, send an updated list */ DBG1(DBG_IKE, "sending address list update using MOBIKE"); - mobike = ike_mobike_create(&this->public, TRUE); - mobike->addresses(mobike); - this->task_manager->queue_task(this->task_manager, - (task_t*)mobike); + this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE); return this->task_manager->initiate(this->task_manager); } return SUCCESS; @@ -2007,9 +1897,7 @@ METHOD(ike_sa_t, roam, status_t, { DBG1(DBG_IKE, "requesting address change using MOBIKE"); } - mobike = ike_mobike_create(&this->public, TRUE); - mobike->roam(mobike, address); - this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + this->task_manager->queue_mobike(this->task_manager, TRUE, address); return this->task_manager->initiate(this->task_manager); } @@ -2044,6 +1932,18 @@ METHOD(ike_sa_t, create_task_enumerator, enumerator_t*, return this->task_manager->create_task_enumerator(this->task_manager, queue); } +METHOD(ike_sa_t, flush_queue, void, + private_ike_sa_t *this, task_queue_t queue) +{ + this->task_manager->flush_queue(this->task_manager, queue); +} + +METHOD(ike_sa_t, queue_task, void, + private_ike_sa_t *this, task_t *task) +{ + this->task_manager->queue_task(this->task_manager, task); +} + METHOD(ike_sa_t, inherit, void, private_ike_sa_t *this, ike_sa_t *other_public) { @@ -2052,6 +1952,7 @@ METHOD(ike_sa_t, inherit, void, attribute_entry_t *entry; enumerator_t *enumerator; auth_cfg_t *cfg; + host_t *vip; /* apply hosts and ids */ this->my_host->destroy(this->my_host); @@ -2063,16 +1964,15 @@ METHOD(ike_sa_t, inherit, void, this->my_id = other->my_id->clone(other->my_id); this->other_id = other->other_id->clone(other->other_id); - /* apply virtual assigned IPs... */ - if (other->my_virtual_ip) + /* apply assigned virtual IPs... */ + while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS) { - this->my_virtual_ip = other->my_virtual_ip; - other->my_virtual_ip = NULL; + other->my_vips->insert_first(other->my_vips, vip); } - if (other->other_virtual_ip) + while (this->other_vips->remove_last(this->other_vips, + (void**)&vip) == SUCCESS) { - this->other_virtual_ip = other->other_virtual_ip; - other->other_virtual_ip = NULL; + other->other_vips->insert_first(other->other_vips, vip); } /* authentication information */ @@ -2147,11 +2047,12 @@ METHOD(ike_sa_t, destroy, void, private_ike_sa_t *this) { attribute_entry_t *entry; + host_t *vip; charon->bus->set_sa(charon->bus, &this->public); set_state(this, IKE_DESTROYING); - this->task_manager->destroy(this->task_manager); + DESTROY_IF(this->task_manager); /* remove attributes first, as we pass the IKE_SA to the handler */ while (this->attributes->remove_last(this->attributes, @@ -2169,24 +2070,31 @@ METHOD(ike_sa_t, destroy, void, /* unset SA after here to avoid usage by the listeners */ charon->bus->set_sa(charon->bus, NULL); - this->keymat->destroy(this->keymat); + DESTROY_IF(this->keymat); - if (this->my_virtual_ip) + while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS) { - hydra->kernel_interface->del_ip(hydra->kernel_interface, - this->my_virtual_ip); - this->my_virtual_ip->destroy(this->my_virtual_ip); + hydra->kernel_interface->del_ip(hydra->kernel_interface, vip); + vip->destroy(vip); } - if (this->other_virtual_ip) + this->my_vips->destroy(this->my_vips); + while (this->other_vips->remove_last(this->other_vips, + (void**)&vip) == SUCCESS) { - if (this->peer_cfg && this->peer_cfg->get_pool(this->peer_cfg)) + if (this->peer_cfg) { - hydra->attributes->release_address(hydra->attributes, - this->peer_cfg->get_pool(this->peer_cfg), - this->other_virtual_ip, get_other_eap_id(this)); + linked_list_t *pools; + identification_t *id; + + id = get_other_eap_id(this); + pools = linked_list_create_from_enumerator( + this->peer_cfg->create_pool_enumerator(this->peer_cfg)); + hydra->attributes->release_address(hydra->attributes, pools, vip, id); + pools->destroy(pools); } - this->other_virtual_ip->destroy(this->other_virtual_ip); + vip->destroy(vip); } + this->other_vips->destroy(this->other_vips); this->peer_addresses->destroy_offset(this->peer_addresses, offsetof(host_t, destroy)); #ifdef ME @@ -2224,19 +2132,32 @@ METHOD(ike_sa_t, destroy, void, /* * Described in header. */ -ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) +ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, + ike_version_t version) { private_ike_sa_t *this; static u_int32_t unique_id = 0; + if (version == IKE_ANY) + { /* prefer IKEv2 if protocol not specified */ +#ifdef USE_IKEV2 + version = IKEV2; +#else + version = IKEV1; +#endif + } + INIT(this, .public = { + .get_version = _get_version, .get_state = _get_state, .set_state = _set_state, .get_name = _get_name, .get_statistic = _get_statistic, + .set_statistic = _set_statistic, .process_message = _process_message, .initiate = _initiate, + .retry_initiate = _retry_initiate, .get_ike_cfg = _get_ike_cfg, .set_ike_cfg = _set_ike_cfg, .get_peer_cfg = _get_peer_cfg, @@ -2292,11 +2213,14 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .generate_message = _generate_message, .reset = _reset, .get_unique_id = _get_unique_id, - .set_virtual_ip = _set_virtual_ip, - .get_virtual_ip = _get_virtual_ip, + .add_virtual_ip = _add_virtual_ip, + .clear_virtual_ips = _clear_virtual_ips, + .create_virtual_ip_enumerator = _create_virtual_ip_enumerator, .add_configuration_attribute = _add_configuration_attribute, .set_kmaddress = _set_kmaddress, .create_task_enumerator = _create_task_enumerator, + .flush_queue = _flush_queue, + .queue_task = _queue_task, #ifdef ME .act_as_mediation_server = _act_as_mediation_server, .get_server_reflexive_host = _get_server_reflexive_host, @@ -2310,12 +2234,13 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) #endif /* ME */ }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), + .version = version, .child_sas = linked_list_create(), .my_host = host_create_any(AF_INET), .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), .other_id = identification_create_from_encoding(ID_ANY, chunk_empty), - .keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)), + .keymat = keymat_create(version, initiator), .state = IKE_CREATED, .stats[STAT_INBOUND] = time_monotonic(NULL), .stats[STAT_OUTBOUND] = time_monotonic(NULL), @@ -2325,12 +2250,31 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .other_auths = linked_list_create(), .unique_id = ++unique_id, .peer_addresses = linked_list_create(), + .my_vips = linked_list_create(), + .other_vips = linked_list_create(), .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, - "charon.keep_alive", KEEPALIVE_INTERVAL), + "%s.keep_alive", KEEPALIVE_INTERVAL, charon->name), + .retry_initiate_interval = lib->settings->get_time(lib->settings, + "%s.retry_initiate_interval", 0, charon->name), + .flush_auth_cfg = lib->settings->get_bool(lib->settings, + "%s.flush_auth_cfg", FALSE, charon->name), ); + + if (version == IKEV2) + { /* always supported with IKEv2 */ + enable_extension(this, EXT_DPD); + } + this->task_manager = task_manager_create(&this->public); - this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); + this->my_host->set_port(this->my_host, + charon->socket->get_port(charon->socket, FALSE)); + if (!this->task_manager || !this->keymat) + { + DBG1(DBG_IKE, "IKE version %d not supported", this->version); + destroy(this); + return NULL; + } return &this->public; } diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 537565e89..af741c799 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -37,11 +37,13 @@ typedef struct ike_sa_t ike_sa_t; #include #include #include +#include #include #include #include #include #include +#include /** * Timeout in seconds after that a half open IKE_SA gets deleted. @@ -69,7 +71,7 @@ typedef struct ike_sa_t ike_sa_t; enum ike_extension_t { /** - * peer supports NAT traversal as specified in RFC4306 + * peer supports NAT traversal as specified in RFC4306 or RFC3947 */ EXT_NATT = (1<<0), @@ -102,6 +104,21 @@ enum ike_extension_t { * peer is probably a Windows 7 RAS client */ EXT_MS_WINDOWS = (1<<6), + + /** + * peer supports XAuth authentication, draft-ietf-ipsec-isakmp-xauth-06 + */ + EXT_XAUTH = (1<<7), + + /** + * peer supports DPD detection, RFC 3706 (or IKEv2) + */ + EXT_DPD = (1<<8), + + /** + * peer supports Cisco Unity configuration attributes + */ + EXT_CISCO_UNITY = (1<<9), }; /** @@ -148,6 +165,21 @@ enum ike_condition_t { * IKE_SA is stale, the peer is currently unreachable (MOBIKE) */ COND_STALE = (1<<7), + + /** + * Initial contact received + */ + COND_INIT_CONTACT_SEEN = (1<<8), + + /** + * Peer has been authenticated using XAuth + */ + COND_XAUTH_AUTHENTICATED = (1<<9), + + /** + * This IKE_SA is currently being reauthenticated + */ + COND_REAUTHENTICATING = (1<<10), }; /** @@ -269,6 +301,11 @@ struct ike_sa_t { */ ike_sa_id_t* (*get_id) (ike_sa_t *this); + /** + * Gets the IKE version of the SA + */ + ike_version_t (*get_version)(ike_sa_t *this); + /** * Get the numerical ID uniquely defining this IKE_SA. * @@ -288,7 +325,7 @@ struct ike_sa_t { * * @param state state to set for the IKE_SA */ - void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa); + void (*set_state) (ike_sa_t *this, ike_sa_state_t state); /** * Get the name of the connection this IKE_SA uses. @@ -305,6 +342,14 @@ struct ike_sa_t { */ u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind); + /** + * Set statistic value of the IKE_SA. + * + * @param kind kind of value to update + * @param value value as integer + */ + void (*set_statistic)(ike_sa_t *this, statistic_t kind, u_int32_t value); + /** * Get the own host address. * @@ -660,6 +705,15 @@ struct ike_sa_t { u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr); + /** + * Retry initiation of this IKE_SA after it got deferred previously. + * + * @return + * - SUCCESS if initiation deferred or started + * - DESTROY_ME if initiation failed + */ + status_t (*retry_initiate) (ike_sa_t *this); + /** * Initiates the deletion of an IKE_SA. * @@ -821,11 +875,13 @@ struct ike_sa_t { * * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA + * @param expired TRUE if CHILD_SA is expired * @return * - NOT_FOUND, if IKE_SA has no such CHILD_SA * - SUCCESS, if delete message sent */ - status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); + status_t (*delete_child_sa)(ike_sa_t *this, protocol_id_t protocol, + u_int32_t spi, bool expired); /** * Destroy a CHILD SA with the specified protocol/SPI. @@ -880,7 +936,7 @@ struct ike_sa_t { status_t (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); /** - * Set the virtual IP to use for this IKE_SA and its children. + * Add a virtual IP to use for this IKE_SA and its children. * * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same * lifetime as the IKE_SA. @@ -888,15 +944,22 @@ struct ike_sa_t { * @param local TRUE to set local address, FALSE for remote * @param ip IP to set as virtual IP */ - void (*set_virtual_ip) (ike_sa_t *this, bool local, host_t *ip); + void (*add_virtual_ip) (ike_sa_t *this, bool local, host_t *ip); /** - * Get the virtual IP configured. + * Clear all virtual IPs stored on this IKE_SA. + * + * @param local TRUE to clear local addresses, FALSE for remote + */ + void (*clear_virtual_ips) (ike_sa_t *this, bool local); + + /** + * Create an enumerator over virtual IPs. * * @param local TRUE to get local virtual IP, FALSE for remote - * @return host_t *virtual IP + * @return enumerator over host_t* */ - host_t* (*get_virtual_ip) (ike_sa_t *this, bool local); + enumerator_t* (*create_virtual_ip_enumerator) (ike_sa_t *this, bool local); /** * Register a configuration attribute to the IKE_SA. @@ -932,6 +995,20 @@ struct ike_sa_t { */ enumerator_t* (*create_task_enumerator)(ike_sa_t *this, task_queue_t queue); + /** + * Flush a task queue, cancelling all tasks in it. + * + * @param queue queue type to flush + */ + void (*flush_queue)(ike_sa_t *this, task_queue_t queue); + + /** + * Queue a task for initiaton to the task manager. + * + * @param task task to queue + */ + void (*queue_task)(ike_sa_t *this, task_t *task); + /** * Inherit all attributes of other to this after rekeying. * @@ -955,11 +1032,14 @@ struct ike_sa_t { }; /** - * Creates an ike_sa_t object with a specific ID. + * Creates an ike_sa_t object with a specific ID and IKE version. * - * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA + * @param ike_sa_id ike_sa_id_t to associate with new IKE_SA/ISAKMP_SA + * @param initiator TRUE to create this IKE_SA as initiator + * @param version IKE version of this SA * @return ike_sa_t object */ -ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id); +ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, + ike_version_t version); #endif /** IKE_SA_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa_id.c b/src/libcharon/sa/ike_sa_id.c index bea4c2124..0f0f1ab63 100644 --- a/src/libcharon/sa/ike_sa_id.c +++ b/src/libcharon/sa/ike_sa_id.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -30,13 +31,18 @@ struct private_ike_sa_id_t { */ ike_sa_id_t public; + /** + * Major IKE version of IKE_SA. + */ + u_int8_t ike_version; + /** - * SPI of Initiator. + * SPI of initiator. */ u_int64_t initiator_spi; /** - * SPI of Responder. + * SPI of responder. */ u_int64_t responder_spi; @@ -46,6 +52,12 @@ struct private_ike_sa_id_t { bool is_initiator_flag; }; +METHOD(ike_sa_id_t, get_ike_version, u_int8_t, + private_ike_sa_id_t *this) +{ + return this->ike_version; +} + METHOD(ike_sa_id_t, set_responder_spi, void, private_ike_sa_id_t *this, u_int64_t responder_spi) { @@ -77,23 +89,15 @@ METHOD(ike_sa_id_t, equals, bool, { return FALSE; } - if ((this->is_initiator_flag == other->is_initiator_flag) && - (this->initiator_spi == other->initiator_spi) && - (this->responder_spi == other->responder_spi)) - { - /* private_ike_sa_id's are equal */ - return TRUE; - } - else - { - /* private_ike_sa_id's are not equal */ - return FALSE; - } + return this->ike_version == other->ike_version && + this->initiator_spi == other->initiator_spi && + this->responder_spi == other->responder_spi; } METHOD(ike_sa_id_t, replace_values, void, private_ike_sa_id_t *this, private_ike_sa_id_t *other) { + this->ike_version = other->ike_version; this->initiator_spi = other->initiator_spi; this->responder_spi = other->responder_spi; this->is_initiator_flag = other->is_initiator_flag; @@ -108,22 +112,15 @@ METHOD(ike_sa_id_t, is_initiator, bool, METHOD(ike_sa_id_t, switch_initiator, bool, private_ike_sa_id_t *this) { - if (this->is_initiator_flag) - { - this->is_initiator_flag = FALSE; - } - else - { - this->is_initiator_flag = TRUE; - } + this->is_initiator_flag = !this->is_initiator_flag; return this->is_initiator_flag; } METHOD(ike_sa_id_t, clone_, ike_sa_id_t*, private_ike_sa_id_t *this) { - return ike_sa_id_create(this->initiator_spi, this->responder_spi, - this->is_initiator_flag); + return ike_sa_id_create(this->ike_version, this->initiator_spi, + this->responder_spi, this->is_initiator_flag); } METHOD(ike_sa_id_t, destroy, void, @@ -135,13 +132,14 @@ METHOD(ike_sa_id_t, destroy, void, /* * Described in header. */ -ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, - bool is_initiator_flag) +ike_sa_id_t * ike_sa_id_create(u_int8_t ike_version, u_int64_t initiator_spi, + u_int64_t responder_spi, bool is_initiator_flag) { private_ike_sa_id_t *this; INIT(this, .public = { + .get_ike_version = _get_ike_version, .set_responder_spi = _set_responder_spi, .set_initiator_spi = _set_initiator_spi, .get_responder_spi = _get_responder_spi, @@ -153,6 +151,7 @@ ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, .clone = _clone_, .destroy = _destroy, }, + .ike_version = ike_version, .initiator_spi = initiator_spi, .responder_spi = responder_spi, .is_initiator_flag = is_initiator_flag, diff --git a/src/libcharon/sa/ike_sa_id.h b/src/libcharon/sa/ike_sa_id.h index fb55359bc..227683d1c 100644 --- a/src/libcharon/sa/ike_sa_id.h +++ b/src/libcharon/sa/ike_sa_id.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -29,12 +30,19 @@ typedef struct ike_sa_id_t ike_sa_id_t; /** * An object of type ike_sa_id_t is used to identify an IKE_SA. * - * An IKE_SA is identified by its initiator and responder spi's. - * Additionally it contains the role of the actual running IKEv2 daemon - * for the specific IKE_SA (original initiator or responder). + * An IKE_SA is identified by its initiator and responder SPIs. + * Additionally, it contains the major IKE version of the IKE_SA and, for IKEv2, + * the role of the daemon (original initiator or responder). */ struct ike_sa_id_t { + /** + * Get the major IKE version of this IKE_SA. + * + * @return IKE version + */ + u_int8_t (*get_ike_version) (ike_sa_id_t *this); + /** * Set the SPI of the responder. * @@ -68,10 +76,12 @@ struct ike_sa_id_t { /** * Check if two ike_sa_id_t objects are equal. * - * Two ike_sa_id_t objects are equal if both SPI values and the role matches. + * Two ike_sa_id_t objects are equal if version and both SPI values match. + * The role is not compared. * * @param other ike_sa_id_t object to check if equal - * @return TRUE if given ike_sa_id_t are equal, FALSE otherwise + * @return TRUE if given ike_sa_id_t are equal, + * FALSE otherwise */ bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other); @@ -93,9 +103,9 @@ struct ike_sa_id_t { bool (*is_initiator) (ike_sa_id_t *this); /** - * Switche the original initiator flag. + * Switch the original initiator flag. * - * @return TRUE if we are the original initiator after switch, FALSE otherwise + * @return new value if initiator flag. */ bool (*switch_initiator) (ike_sa_id_t *this); @@ -113,14 +123,15 @@ struct ike_sa_id_t { }; /** - * Creates an ike_sa_id_t object with specific SPI's and defined role. + * Creates an ike_sa_id_t object. * + * @param ike_version major IKE version * @param initiator_spi initiators SPI * @param responder_spi responders SPI * @param is_initiaor TRUE if we are the original initiator * @return ike_sa_id_t object */ -ike_sa_id_t * ike_sa_id_create(u_int64_t initiator_spi, u_int64_t responder_spi, - bool is_initiaor); +ike_sa_id_t * ike_sa_id_create(u_int8_t ike_version, u_int64_t initiator_spi, + u_int64_t responder_spi, bool is_initiaor); #endif /** IKE_SA_ID_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 731ae6007..a396235c2 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2011 revosec AG - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -156,18 +156,6 @@ static entry_t *entry_create() return this; } -/** - * Function that matches entry_t objects by initiator SPI and the hash of the - * IKE_SA_INIT message. - */ -static bool entry_match_by_hash(entry_t *entry, ike_sa_id_t *id, chunk_t *hash) -{ - return id->get_responder_spi(id) == 0 && - id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id) && - chunk_equals(*hash, entry->init_hash); -} - /** * Function that matches entry_t objects by ike_sa_id_t. */ @@ -179,7 +167,6 @@ static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id) } if ((id->get_responder_spi(id) == 0 || entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0) && - id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id)) { /* this is TRUE for IKE_SAs that we initiated but have not yet received a response */ @@ -201,8 +188,19 @@ static bool entry_match_by_sa(entry_t *entry, ike_sa_t *ike_sa) */ static u_int ike_sa_id_hash(ike_sa_id_t *ike_sa_id) { - /* we always use initiator spi as key */ - return ike_sa_id->get_initiator_spi(ike_sa_id); + /* IKEv2 does not mandate random SPIs (RFC 5996, 2.6), they just have to be + * locally unique, so we use our randomly allocated SPI whether we are + * initiator or responder to ensure a good distribution. The latter is not + * possible for IKEv1 as we don't know whether we are original initiator or + * not (based on the IKE header). But as RFC 2408, section 2.5.3 proposes + * SPIs (Cookies) to be allocated near random (we allocate them randomly + * anyway) it seems safe to always use the initiator SPI. */ + if (ike_sa_id->get_ike_version(ike_sa_id) == IKEV1_MAJOR_VERSION || + ike_sa_id->is_initiator(ike_sa_id)) + { + return ike_sa_id->get_initiator_spi(ike_sa_id); + } + return ike_sa_id->get_responder_spi(ike_sa_id); } typedef struct half_open_t half_open_t; @@ -227,14 +225,6 @@ static void half_open_destroy(half_open_t *this) free(this); } -/** - * Function that matches half_open_t objects by the given IP address chunk. - */ -static bool half_open_match(half_open_t *half_open, chunk_t *addr) -{ - return chunk_equals(*addr, half_open->other); -} - typedef struct connected_peers_t connected_peers_t; struct connected_peers_t { @@ -262,15 +252,25 @@ static void connected_peers_destroy(connected_peers_t *this) /** * Function that matches connected_peers_t objects by the given ids. */ -static bool connected_peers_match(connected_peers_t *connected_peers, +static inline bool connected_peers_match(connected_peers_t *connected_peers, identification_t *my_id, identification_t *other_id, - uintptr_t family) + int family) { return my_id->equals(my_id, connected_peers->my_id) && other_id->equals(other_id, connected_peers->other_id) && - family == connected_peers->family; + (!family || family == connected_peers->family); } +typedef struct init_hash_t init_hash_t; + +struct init_hash_t { + /** hash of IKE_SA_INIT or initial phase1 message (data is not cloned) */ + chunk_t hash; + + /** our SPI allocated for the IKE_SA based on this message */ + u_int64_t our_spi; +}; + typedef struct segment_t segment_t; /** @@ -298,6 +298,20 @@ struct shareable_segment_t { u_int count; }; +typedef struct table_item_t table_item_t; + +/** + * Instead of using linked_list_t for each bucket we store the data in our own + * list to save memory. + */ +struct table_item_t { + /** data of this item */ + void *value; + + /** next item in the overflow list */ + table_item_t *next; +}; + typedef struct private_ike_sa_manager_t private_ike_sa_manager_t; /** @@ -312,7 +326,7 @@ struct private_ike_sa_manager_t { /** * Hash table with entries for the ike_sa_t objects. */ - linked_list_t **ike_sa_table; + table_item_t **ike_sa_table; /** * The size of the hash table. @@ -342,7 +356,7 @@ struct private_ike_sa_manager_t { /** * Hash table with half_open_t objects. */ - linked_list_t **half_open_table; + table_item_t **half_open_table; /** * Segments of the "half-open" hash table. @@ -352,13 +366,23 @@ struct private_ike_sa_manager_t { /** * Hash table with connected_peers_t objects. */ - linked_list_t **connected_peers_table; + table_item_t **connected_peers_table; /** * Segments of the "connected peers" hash table. */ shareable_segment_t *connected_peers_segments; + /** + * Hash table with init_hash_t objects. + */ + table_item_t **init_hashes_table; + + /** + * Segments of the "hashes" hash table. + */ + segment_t *init_hashes_segments; + /** * RNG to get random SPIs for our side */ @@ -379,10 +403,10 @@ struct private_ike_sa_manager_t { * Acquire a lock to access the segment of the table row with the given index. * It also works with the segment index directly. */ -static void lock_single_segment(private_ike_sa_manager_t *this, u_int index) +static inline void lock_single_segment(private_ike_sa_manager_t *this, + u_int index) { mutex_t *lock = this->segments[index & this->segment_mask].mutex; - lock->lock(lock); } @@ -390,10 +414,10 @@ static void lock_single_segment(private_ike_sa_manager_t *this, u_int index) * Release the lock required to access the segment of the table row with the given index. * It also works with the segment index directly. */ -static void unlock_single_segment(private_ike_sa_manager_t *this, u_int index) +static inline void unlock_single_segment(private_ike_sa_manager_t *this, + u_int index) { mutex_t *lock = this->segments[index & this->segment_mask].mutex; - lock->unlock(lock); } @@ -456,9 +480,14 @@ struct private_enumerator_t { u_int row; /** - * enumerator for the current table row + * current table item + */ + table_item_t *current; + + /** + * previous table item */ - enumerator_t *current; + table_item_t *prev; }; METHOD(enumerator_t, enumerate, bool, @@ -473,33 +502,23 @@ METHOD(enumerator_t, enumerate, bool, { while (this->row < this->manager->table_size) { + this->prev = this->current; if (this->current) { - entry_t *item; - - if (this->current->enumerate(this->current, &item)) - { - *entry = this->entry = item; - *segment = this->segment; - return TRUE; - } - this->current->destroy(this->current); - this->current = NULL; - unlock_single_segment(this->manager, this->segment); + this->current = this->current->next; } else { - linked_list_t *list; - lock_single_segment(this->manager, this->segment); - if ((list = this->manager->ike_sa_table[this->row]) != NULL && - list->get_count(list)) - { - this->current = list->create_enumerator(list); - continue; - } - unlock_single_segment(this->manager, this->segment); + this->current = this->manager->ike_sa_table[this->row]; } + if (this->current) + { + *entry = this->entry = this->current->value; + *segment = this->segment; + return TRUE; + } + unlock_single_segment(this->manager, this->segment); this->row += this->manager->segment_count; } this->segment++; @@ -517,7 +536,6 @@ METHOD(enumerator_t, enumerator_destroy, void, } if (this->current) { - this->current->destroy(this->current); unlock_single_segment(this->manager, this->segment); } free(this); @@ -546,19 +564,23 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this) */ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) { - linked_list_t *list; + table_item_t *current, *item; u_int row, segment; + INIT(item, + .value = entry, + ); + row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; segment = row & this->segment_mask; lock_single_segment(this, segment); - list = this->ike_sa_table[row]; - if (!list) - { - list = this->ike_sa_table[row] = linked_list_create(); + current = this->ike_sa_table[row]; + if (current) + { /* insert at the front of current bucket */ + item->next = current; } - list->insert_last(list, entry); + this->ike_sa_table[row] = item; this->segments[segment].count++; return segment; } @@ -569,28 +591,30 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) */ static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) { - linked_list_t *list; + table_item_t *item, *prev = NULL; u_int row, segment; row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; segment = row & this->segment_mask; - list = this->ike_sa_table[row]; - if (list) + item = this->ike_sa_table[row]; + while (item) { - entry_t *current; - enumerator_t *enumerator; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, ¤t)) + if (item->value == entry) { - if (current == entry) + if (prev) { - list->remove_at(list, enumerator); - this->segments[segment].count--; - break; + prev->next = item->next; } + else + { + this->ike_sa_table[row] = item->next; + } + this->segments[segment].count--; + free(item); + break; } - enumerator->destroy(enumerator); + prev = item; + item = item->next; } } @@ -602,9 +626,21 @@ static void remove_entry_at(private_enumerator_t *this) this->entry = NULL; if (this->current) { - linked_list_t *list = this->manager->ike_sa_table[this->row]; - list->remove_at(list, this->current); + table_item_t *current = this->current; + this->manager->segments[this->segment].count--; + this->current = this->prev; + + if (this->prev) + { + this->prev->next = current->next; + } + else + { + this->manager->ike_sa_table[this->row] = current->next; + unlock_single_segment(this->manager, this->segment); + } + free(current); } } @@ -614,26 +650,26 @@ static void remove_entry_at(private_enumerator_t *this) */ static status_t get_entry_by_match_function(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment, - linked_list_match_t match, void *p1, void *p2) + linked_list_match_t match, void *param) { - entry_t *current; - linked_list_t *list; + table_item_t *item; u_int row, seg; row = ike_sa_id_hash(ike_sa_id) & this->table_mask; seg = row & this->segment_mask; lock_single_segment(this, seg); - list = this->ike_sa_table[row]; - if (list) + item = this->ike_sa_table[row]; + while (item) { - if (list->find_first(list, match, (void**)¤t, p1, p2) == SUCCESS) + if (match(item->value, param)) { - *entry = current; + *entry = item->value; *segment = seg; /* the locked segment has to be unlocked by the caller */ return SUCCESS; } + item = item->next; } unlock_single_segment(this, seg); return NOT_FOUND; @@ -647,18 +683,7 @@ static status_t get_entry_by_id(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment) { return get_entry_by_match_function(this, ike_sa_id, entry, segment, - (linked_list_match_t)entry_match_by_id, ike_sa_id, NULL); -} - -/** - * Find an entry by initiator SPI and IKE_SA_INIT hash. - * Note: On SUCCESS, the caller has to unlock the segment. - */ -static status_t get_entry_by_hash(private_ike_sa_manager_t *this, - ike_sa_id_t *ike_sa_id, chunk_t hash, entry_t **entry, u_int *segment) -{ - return get_entry_by_match_function(this, ike_sa_id, entry, segment, - (linked_list_match_t)entry_match_by_hash, ike_sa_id, &hash); + (linked_list_match_t)entry_match_by_id, ike_sa_id); } /** @@ -669,7 +694,7 @@ static status_t get_entry_by_sa(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id, ike_sa_t *ike_sa, entry_t **entry, u_int *segment) { return get_entry_by_match_function(this, ike_sa_id, entry, segment, - (linked_list_match_t)entry_match_by_sa, ike_sa, NULL); + (linked_list_match_t)entry_match_by_sa, ike_sa); } /** @@ -707,44 +732,43 @@ static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry, */ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry) { - half_open_t *half_open = NULL; - linked_list_t *list; - chunk_t addr; + table_item_t *item; u_int row, segment; rwlock_t *lock; + half_open_t *half_open; + chunk_t addr; addr = entry->other->get_address(entry->other); row = chunk_hash(addr) & this->table_mask; segment = row & this->segment_mask; lock = this->half_open_segments[segment].lock; lock->write_lock(lock); - list = this->half_open_table[row]; - if (list) + item = this->half_open_table[row]; + while (item) { - half_open_t *current; + half_open = item->value; - if (list->find_first(list, (linked_list_match_t)half_open_match, - (void**)¤t, &addr) == SUCCESS) + if (chunk_equals(addr, half_open->other)) { - half_open = current; half_open->count++; - this->half_open_segments[segment].count++; + break; } - } - else - { - list = this->half_open_table[row] = linked_list_create(); + item = item->next; } - if (!half_open) + if (!item) { INIT(half_open, .other = chunk_clone(addr), .count = 1, ); - list->insert_last(list, half_open); - this->half_open_segments[segment].count++; + INIT(item, + .value = half_open, + .next = this->half_open_table[row], + ); + this->half_open_table[row] = item; } + this->half_open_segments[segment].count++; lock->unlock(lock); } @@ -753,37 +777,41 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry) */ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry) { - linked_list_t *list; - chunk_t addr; + table_item_t *item, *prev = NULL; u_int row, segment; rwlock_t *lock; + chunk_t addr; addr = entry->other->get_address(entry->other); row = chunk_hash(addr) & this->table_mask; segment = row & this->segment_mask; lock = this->half_open_segments[segment].lock; lock->write_lock(lock); - list = this->half_open_table[row]; - if (list) + item = this->half_open_table[row]; + while (item) { - half_open_t *current; - enumerator_t *enumerator; + half_open_t *half_open = item->value; - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, ¤t)) + if (chunk_equals(addr, half_open->other)) { - if (half_open_match(current, &addr)) + if (--half_open->count == 0) { - if (--current->count == 0) + if (prev) { - list->remove_at(list, enumerator); - half_open_destroy(current); + prev->next = item->next; } - this->half_open_segments[segment].count--; - break; + else + { + this->half_open_table[row] = item->next; + } + half_open_destroy(half_open); + free(item); } + this->half_open_segments[segment].count--; + break; } - enumerator->destroy(enumerator); + prev = item; + item = item->next; } lock->unlock(lock); } @@ -793,28 +821,28 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry) */ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) { - connected_peers_t *connected_peers = NULL; - chunk_t my_id, other_id; - linked_list_t *list; + table_item_t *item; u_int row, segment; rwlock_t *lock; + connected_peers_t *connected_peers; + chunk_t my_id, other_id; + int family; my_id = entry->my_id->get_encoding(entry->my_id); other_id = entry->other_id->get_encoding(entry->other_id); + family = entry->other->get_family(entry->other); row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; segment = row & this->segment_mask; lock = this->connected_peers_segments[segment].lock; lock->write_lock(lock); - list = this->connected_peers_table[row]; - if (list) + item = this->connected_peers_table[row]; + while (item) { - connected_peers_t *current; + connected_peers = item->value; - if (list->find_first(list, (linked_list_match_t)connected_peers_match, - (void**)¤t, entry->my_id, entry->other_id, - (uintptr_t)entry->other->get_family(entry->other)) == SUCCESS) + if (connected_peers_match(connected_peers, entry->my_id, + entry->other_id, family)) { - connected_peers = current; if (connected_peers->sas->find_first(connected_peers->sas, (linked_list_match_t)entry->ike_sa_id->equals, NULL, entry->ike_sa_id) == SUCCESS) @@ -822,22 +850,24 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) lock->unlock(lock); return; } + break; } - } - else - { - list = this->connected_peers_table[row] = linked_list_create(); + item = item->next; } - if (!connected_peers) + if (!item) { INIT(connected_peers, .my_id = entry->my_id->clone(entry->my_id), .other_id = entry->other_id->clone(entry->other_id), - .family = entry->other->get_family(entry->other), + .family = family, .sas = linked_list_create(), ); - list->insert_last(list, connected_peers); + INIT(item, + .value = connected_peers, + .next = this->connected_peers_table[row], + ); + this->connected_peers_table[row] = item; } connected_peers->sas->insert_last(connected_peers->sas, entry->ike_sa_id->clone(entry->ike_sa_id)); @@ -850,54 +880,61 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) */ static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) { - chunk_t my_id, other_id; - linked_list_t *list; + table_item_t *item, *prev = NULL; u_int row, segment; rwlock_t *lock; + chunk_t my_id, other_id; + int family; my_id = entry->my_id->get_encoding(entry->my_id); other_id = entry->other_id->get_encoding(entry->other_id); + family = entry->other->get_family(entry->other); + row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; segment = row & this->segment_mask; lock = this->connected_peers_segments[segment].lock; lock->write_lock(lock); - list = this->connected_peers_table[row]; - if (list) + item = this->connected_peers_table[row]; + while (item) { - connected_peers_t *current; - enumerator_t *enumerator; + connected_peers_t *current = item->value; - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, ¤t)) + if (connected_peers_match(current, entry->my_id, entry->other_id, + family)) { - if (connected_peers_match(current, entry->my_id, entry->other_id, - (uintptr_t)entry->other->get_family(entry->other))) - { - ike_sa_id_t *ike_sa_id; - enumerator_t *inner; + enumerator_t *enumerator; + ike_sa_id_t *ike_sa_id; - inner = current->sas->create_enumerator(current->sas); - while (inner->enumerate(inner, &ike_sa_id)) + enumerator = current->sas->create_enumerator(current->sas); + while (enumerator->enumerate(enumerator, &ike_sa_id)) + { + if (ike_sa_id->equals(ike_sa_id, entry->ike_sa_id)) { - if (ike_sa_id->equals(ike_sa_id, entry->ike_sa_id)) - { - current->sas->remove_at(current->sas, inner); - ike_sa_id->destroy(ike_sa_id); - this->connected_peers_segments[segment].count--; - break; - } + current->sas->remove_at(current->sas, enumerator); + ike_sa_id->destroy(ike_sa_id); + this->connected_peers_segments[segment].count--; + break; } - inner->destroy(inner); - if (current->sas->get_count(current->sas) == 0) + } + enumerator->destroy(enumerator); + if (current->sas->get_count(current->sas) == 0) + { + if (prev) { - list->remove_at(list, enumerator); - connected_peers_destroy(current); + prev->next = item->next; } - break; + else + { + this->connected_peers_table[row] = item->next; + } + connected_peers_destroy(current); + free(item); } + break; } - enumerator->destroy(enumerator); + prev = item; + item = item->next; } lock->unlock(lock); } @@ -907,13 +944,143 @@ static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entr */ static u_int64_t get_spi(private_ike_sa_manager_t *this) { - u_int64_t spi = 0; + u_int64_t spi; + + if (this->rng && + this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi)) + { + return spi; + } + return 0; +} + +/** + * Calculate the hash of the initial IKE message. Memory for the hash is + * allocated on success. + * + * @returns TRUE on success + */ +static bool get_init_hash(private_ike_sa_manager_t *this, message_t *message, + chunk_t *hash) +{ + if (!this->hasher) + { /* this might be the case when flush() has been called */ + return FALSE; + } + if (message->get_exchange_type(message) == ID_PROT) + { /* include the source for Main Mode as the hash will be the same if + * SPIs are reused by two initiators that use the same proposal */ + host_t *src = message->get_source(message); + + if (!this->hasher->allocate_hash(this->hasher, + src->get_address(src), NULL)) + { + return FALSE; + } + } + return this->hasher->allocate_hash(this->hasher, + message->get_packet_data(message), hash); +} + +/** + * Check if we already have created an IKE_SA based on the initial IKE message + * with the given hash. + * If not the hash is stored, the hash data is not(!) cloned. + * + * Also, the local SPI is returned. In case of a retransmit this is already + * stored together with the hash, otherwise it is newly allocated and should + * be used to create the IKE_SA. + * + * @returns ALREADY_DONE if the message with the given hash has been seen before + * NOT_FOUND if the message hash was not found + * FAILED if the SPI allocation failed + */ +static status_t check_and_put_init_hash(private_ike_sa_manager_t *this, + chunk_t init_hash, u_int64_t *our_spi) +{ + table_item_t *item; + u_int row, segment; + mutex_t *mutex; + init_hash_t *init; + u_int64_t spi; - if (this->rng) + row = chunk_hash(init_hash) & this->table_mask; + segment = row & this->segment_mask; + mutex = this->init_hashes_segments[segment].mutex; + mutex->lock(mutex); + item = this->init_hashes_table[row]; + while (item) { - this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi); + init_hash_t *current = item->value; + + if (chunk_equals(init_hash, current->hash)) + { + *our_spi = current->our_spi; + mutex->unlock(mutex); + return ALREADY_DONE; + } + item = item->next; + } + + spi = get_spi(this); + if (!spi) + { + return FAILED; } - return spi; + + INIT(init, + .hash = { + .len = init_hash.len, + .ptr = init_hash.ptr, + }, + .our_spi = spi, + ); + INIT(item, + .value = init, + .next = this->init_hashes_table[row], + ); + this->init_hashes_table[row] = item; + *our_spi = init->our_spi; + mutex->unlock(mutex); + return NOT_FOUND; +} + +/** + * Remove the hash of an initial IKE message from the cache. + */ +static void remove_init_hash(private_ike_sa_manager_t *this, chunk_t init_hash) +{ + table_item_t *item, *prev = NULL; + u_int row, segment; + mutex_t *mutex; + + row = chunk_hash(init_hash) & this->table_mask; + segment = row & this->segment_mask; + mutex = this->init_hashes_segments[segment].mutex; + mutex->lock(mutex); + item = this->init_hashes_table[row]; + while (item) + { + init_hash_t *current = item->value; + + if (chunk_equals(init_hash, current->hash)) + { + if (prev) + { + prev->next = item->next; + } + else + { + this->init_hashes_table[row] = item->next; + } + free(current); + free(item); + break; + } + prev = item; + item = item->next; + } + mutex->unlock(mutex); } METHOD(ike_sa_manager_t, checkout, ike_sa_t*, @@ -941,25 +1108,38 @@ METHOD(ike_sa_manager_t, checkout, ike_sa_t*, } METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, - private_ike_sa_manager_t* this, bool initiator) + private_ike_sa_manager_t* this, ike_version_t version, bool initiator) { ike_sa_id_t *ike_sa_id; ike_sa_t *ike_sa; + u_int8_t ike_version; + u_int64_t spi; + + ike_version = version == IKEV1 ? IKEV1_MAJOR_VERSION : IKEV2_MAJOR_VERSION; + + spi = get_spi(this); + if (!spi) + { + DBG1(DBG_MGR, "failed to allocate SPI for new IKE_SA"); + return NULL; + } if (initiator) { - ike_sa_id = ike_sa_id_create(get_spi(this), 0, TRUE); + ike_sa_id = ike_sa_id_create(ike_version, spi, 0, TRUE); } else { - ike_sa_id = ike_sa_id_create(0, get_spi(this), FALSE); + ike_sa_id = ike_sa_id_create(ike_version, 0, spi, FALSE); } - ike_sa = ike_sa_create(ike_sa_id); + ike_sa = ike_sa_create(ike_sa_id, initiator, version); ike_sa_id->destroy(ike_sa_id); - DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), - ike_sa->get_unique_id(ike_sa)); - + if (ike_sa) + { + DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), + ike_sa->get_unique_id(ike_sa)); + } return ike_sa; } @@ -970,94 +1150,118 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry_t *entry; ike_sa_t *ike_sa = NULL; ike_sa_id_t *id; + ike_version_t ike_version; + bool is_init = FALSE; id = message->get_ike_sa_id(message); + /* clone the IKE_SA ID so we can modify the initiator flag */ id = id->clone(id); id->switch_initiator(id); DBG2(DBG_MGR, "checkout IKE_SA by message"); - if (message->get_request(message) && - message->get_exchange_type(message) == IKE_SA_INIT && - this->hasher) + if (id->get_responder_spi(id) == 0) { - /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */ - chunk_t data, hash; - - data = message->get_packet_data(message); - this->hasher->allocate_hash(this->hasher, data, &hash); - chunk_free(&data); - - if (get_entry_by_hash(this, id, hash, &entry, &segment) == SUCCESS) + if (message->get_major_version(message) == IKEV2_MAJOR_VERSION) { - if (entry->message_id == 0) + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_request(message)) { - unlock_single_segment(this, segment); - chunk_free(&hash); - id->destroy(id); - DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing"); - return NULL; + ike_version = IKEV2; + is_init = TRUE; } - else if (wait_for_entry(this, entry, segment)) + } + else + { + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) { - entry->checked_out = TRUE; - entry->message_id = message->get_message_id(message); - ike_sa = entry->ike_sa; - DBG2(DBG_MGR, "IKE_SA %s[%u] checked out by hash", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + ike_version = IKEV1; + is_init = TRUE; + if (id->is_initiator(id)) + { /* not set in IKEv1, switch back before applying to new SA */ + id->switch_initiator(id); + } } - unlock_single_segment(this, segment); + } + } + + if (is_init) + { + u_int64_t our_spi; + chunk_t hash; + + if (!get_init_hash(this, message, &hash)) + { + DBG1(DBG_MGR, "ignoring message, failed to hash message"); + id->destroy(id); + return NULL; } - if (ike_sa == NULL) + /* ensure this is not a retransmit of an already handled init message */ + switch (check_and_put_init_hash(this, hash, &our_spi)) { - if (id->get_responder_spi(id) == 0 && - message->get_exchange_type(message) == IKE_SA_INIT) - { - /* no IKE_SA found, create a new one */ - id->set_responder_spi(id, get_spi(this)); - entry = entry_create(); - entry->ike_sa = ike_sa_create(id); - entry->ike_sa_id = id->clone(id); + case NOT_FOUND: + { /* we've not seen this packet yet, create a new IKE_SA */ + id->set_responder_spi(id, our_spi); + ike_sa = ike_sa_create(id, FALSE, ike_version); + if (ike_sa) + { + entry = entry_create(); + entry->ike_sa = ike_sa; + entry->ike_sa_id = id->clone(id); - segment = put_entry(this, entry); - entry->checked_out = TRUE; - unlock_single_segment(this, segment); + segment = put_entry(this, entry); + entry->checked_out = TRUE; + unlock_single_segment(this, segment); - entry->message_id = message->get_message_id(message); - entry->init_hash = hash; - ike_sa = entry->ike_sa; + entry->message_id = message->get_message_id(message); + entry->init_hash = hash; - DBG2(DBG_MGR, "created IKE_SA %s[%u]", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + DBG2(DBG_MGR, "created IKE_SA %s[%u]", + ike_sa->get_name(ike_sa), + ike_sa->get_unique_id(ike_sa)); + } + else + { + remove_init_hash(this, hash); + chunk_free(&hash); + DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); + } + id->destroy(id); + charon->bus->set_sa(charon->bus, ike_sa); + return ike_sa; } - else - { + case FAILED: + { /* we failed to allocate an SPI */ chunk_free(&hash); - DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); + id->destroy(id); + DBG1(DBG_MGR, "ignoring message, failed to allocate SPI"); + return NULL; } + case ALREADY_DONE: + default: + break; } - else - { - chunk_free(&hash); - } - id->destroy(id); - charon->bus->set_sa(charon->bus, ike_sa); - return ike_sa; + /* it looks like we already handled this init message to some degree */ + id->set_responder_spi(id, our_spi); + chunk_free(&hash); } if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS) { - /* only check out if we are not processing this request */ + /* only check out in IKEv2 if we are not already processing it */ if (message->get_request(message) && message->get_message_id(message) == entry->message_id) { - DBG1(DBG_MGR, "ignoring request with ID %d, already processing", + DBG1(DBG_MGR, "ignoring request with ID %u, already processing", entry->message_id); } else if (wait_for_entry(this, entry, segment)) { - ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa); + ike_sa_id_t *ike_id; + + ike_id = entry->ike_sa->get_id(entry->ike_sa); entry->checked_out = TRUE; entry->message_id = message->get_message_id(message); if (ike_id->get_responder_spi(ike_id) == 0) @@ -1089,7 +1293,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, if (!this->reuse_ikesa) { /* IKE_SA reuse disable by config */ - ike_sa = checkout_new(this, TRUE); + ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; } @@ -1125,7 +1329,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, if (!ike_sa) { /* no IKE_SA using such a config, hand out a new */ - ike_sa = checkout_new(this, TRUE); + ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); } charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; @@ -1244,6 +1448,7 @@ static bool enumerator_filter_wait(private_ike_sa_manager_t *this, if (wait_for_entry(this, *in, *segment)) { *out = (*in)->ike_sa; + charon->bus->set_sa(charon->bus, *out); return TRUE; } return FALSE; @@ -1260,17 +1465,26 @@ static bool enumerator_filter_skip(private_ike_sa_manager_t *this, !(*in)->checked_out) { *out = (*in)->ike_sa; + charon->bus->set_sa(charon->bus, *out); return TRUE; } return FALSE; } +/** + * Reset threads SA after enumeration + */ +static void reset_sa(void *data) +{ + charon->bus->set_sa(charon->bus, NULL); +} + METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*, private_ike_sa_manager_t* this, bool wait) { return enumerator_create_filter(create_table_enumerator(this), wait ? (void*)enumerator_filter_wait : (void*)enumerator_filter_skip, - this, NULL); + this, reset_sa); } METHOD(ike_sa_manager_t, checkin, void, @@ -1290,7 +1504,7 @@ METHOD(ike_sa_manager_t, checkin, void, ike_sa_id = ike_sa->get_id(ike_sa); my_id = ike_sa->get_my_id(ike_sa); - other_id = ike_sa->get_other_id(ike_sa); + other_id = ike_sa->get_other_eap_id(ike_sa); other = ike_sa->get_other_host(ike_sa); DBG2(DBG_MGR, "checkin IKE_SA %s[%u]", ike_sa->get_name(ike_sa), @@ -1340,9 +1554,21 @@ METHOD(ike_sa_manager_t, checkin, void, } /* apply identities for duplicate test */ - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED || + ike_sa->get_state(ike_sa) == IKE_PASSIVE) && entry->my_id == NULL && entry->other_id == NULL) { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + /* If authenticated and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. */ + if (ike_sa->has_condition(ike_sa, COND_INIT_CONTACT_SEEN)) + { + this->public.check_uniqueness(&this->public, ike_sa, TRUE); + ike_sa->set_condition(ike_sa, COND_INIT_CONTACT_SEEN, FALSE); + } + } + entry->my_id = my_id->clone(my_id); entry->other_id = other_id->clone(other_id); if (!entry->other) @@ -1376,6 +1602,16 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS) { + if (entry->driveout_waiting_threads && entry->driveout_new_threads) + { /* it looks like flush() has been called and the SA is being deleted + * anyway, just check it in */ + DBG2(DBG_MGR, "ignored check-in and destroy of IKE_SA during shutdown"); + entry->checked_out = FALSE; + entry->condvar->broadcast(entry->condvar); + unlock_single_segment(this, segment); + return; + } + /* drive out waiting threads, as we are in hurry */ entry->driveout_waiting_threads = TRUE; /* mark it, so no new threads can get this entry */ @@ -1399,6 +1635,10 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, { remove_connected_peers(this, entry); } + if (entry->init_hash.ptr) + { + remove_init_hash(this, entry->init_hash); + } entry_destroy(entry); @@ -1412,65 +1652,81 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, charon->bus->set_sa(charon->bus, NULL); } -METHOD(ike_sa_manager_t, check_uniqueness, bool, - private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) +/** + * Cleanup function for create_id_enumerator + */ +static void id_enumerator_cleanup(linked_list_t *ids) { - bool cancel = FALSE; - peer_cfg_t *peer_cfg; - unique_policy_t policy; - linked_list_t *list, *duplicate_ids = NULL; - enumerator_t *enumerator; - ike_sa_id_t *duplicate_id = NULL; - identification_t *me, *other; + ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy)); +} + +METHOD(ike_sa_manager_t, create_id_enumerator, enumerator_t*, + private_ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family) +{ + table_item_t *item; u_int row, segment; rwlock_t *lock; - - peer_cfg = ike_sa->get_peer_cfg(ike_sa); - policy = peer_cfg->get_unique_policy(peer_cfg); - if (policy == UNIQUE_NO && !force_replace) - { - return FALSE; - } - - me = ike_sa->get_my_id(ike_sa); - other = ike_sa->get_other_id(ike_sa); + linked_list_t *ids = NULL; row = chunk_hash_inc(other->get_encoding(other), chunk_hash(me->get_encoding(me))) & this->table_mask; segment = row & this->segment_mask; - lock = this->connected_peers_segments[segment & this->segment_mask].lock; + lock = this->connected_peers_segments[segment].lock; lock->read_lock(lock); - list = this->connected_peers_table[row]; - if (list) + item = this->connected_peers_table[row]; + while (item) { - connected_peers_t *current; - host_t *other_host; + connected_peers_t *current = item->value; - other_host = ike_sa->get_other_host(ike_sa); - if (list->find_first(list, (linked_list_match_t)connected_peers_match, - (void**)¤t, me, other, - (uintptr_t)other_host->get_family(other_host)) == SUCCESS) + if (connected_peers_match(current, me, other, family)) { - /* clone the list, so we can release the lock */ - duplicate_ids = current->sas->clone_offset(current->sas, - offsetof(ike_sa_id_t, clone)); + ids = current->sas->clone_offset(current->sas, + offsetof(ike_sa_id_t, clone)); + break; } + item = item->next; } lock->unlock(lock); - if (!duplicate_ids) + if (!ids) + { + return enumerator_create_empty(); + } + return enumerator_create_cleaner(ids->create_enumerator(ids), + (void*)id_enumerator_cleanup, ids); +} + +METHOD(ike_sa_manager_t, check_uniqueness, bool, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) +{ + bool cancel = FALSE; + peer_cfg_t *peer_cfg; + unique_policy_t policy; + enumerator_t *enumerator; + ike_sa_id_t *id = NULL; + identification_t *me, *other; + host_t *other_host; + + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + policy = peer_cfg->get_unique_policy(peer_cfg); + if (policy == UNIQUE_NEVER || (policy == UNIQUE_NO && !force_replace)) { return FALSE; } + me = ike_sa->get_my_id(ike_sa); + other = ike_sa->get_other_eap_id(ike_sa); + other_host = ike_sa->get_other_host(ike_sa); - enumerator = duplicate_ids->create_enumerator(duplicate_ids); - while (enumerator->enumerate(enumerator, &duplicate_id)) + enumerator = create_id_enumerator(this, me, other, + other_host->get_family(other_host)); + while (enumerator->enumerate(enumerator, &id)) { status_t status = SUCCESS; ike_sa_t *duplicate; - duplicate = checkout(this, duplicate_id); + duplicate = checkout(this, id); if (!duplicate) { continue; @@ -1520,7 +1776,6 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, } } enumerator->destroy(enumerator); - duplicate_ids->destroy_offset(duplicate_ids, offsetof(ike_sa_id_t, destroy)); /* reset thread's current IKE_SA after checkin */ charon->bus->set_sa(charon->bus, ike_sa); return cancel; @@ -1530,7 +1785,7 @@ METHOD(ike_sa_manager_t, has_contact, bool, private_ike_sa_manager_t *this, identification_t *me, identification_t *other, int family) { - linked_list_t *list; + table_item_t *item; u_int row, segment; rwlock_t *lock; bool found = FALSE; @@ -1538,16 +1793,17 @@ METHOD(ike_sa_manager_t, has_contact, bool, row = chunk_hash_inc(other->get_encoding(other), chunk_hash(me->get_encoding(me))) & this->table_mask; segment = row & this->segment_mask; - lock = this->connected_peers_segments[segment & this->segment_mask].lock; + lock = this->connected_peers_segments[segment].lock; lock->read_lock(lock); - list = this->connected_peers_table[row]; - if (list) + item = this->connected_peers_table[row]; + while (item) { - if (list->find_first(list, (linked_list_match_t)connected_peers_match, - NULL, me, other, family) == SUCCESS) + if (connected_peers_match(item->value, me, other, family)) { found = TRUE; + break; } + item = item->next; } lock->unlock(lock); @@ -1573,8 +1829,8 @@ METHOD(ike_sa_manager_t, get_count, u_int, METHOD(ike_sa_manager_t, get_half_open_count, u_int, private_ike_sa_manager_t *this, host_t *ip) { - linked_list_t *list; - u_int segment, row; + table_item_t *item; + u_int row, segment; rwlock_t *lock; chunk_t addr; u_int count = 0; @@ -1584,17 +1840,19 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int, addr = ip->get_address(ip); row = chunk_hash(addr) & this->table_mask; segment = row & this->segment_mask; - lock = this->half_open_segments[segment & this->segment_mask].lock; + lock = this->half_open_segments[segment].lock; lock->read_lock(lock); - if ((list = this->half_open_table[row]) != NULL) + item = this->half_open_table[row]; + while (item) { - half_open_t *current; + half_open_t *half_open = item->value; - if (list->find_first(list, (linked_list_match_t)half_open_match, - (void**)¤t, &addr) == SUCCESS) + if (chunk_equals(addr, half_open->other)) { - count = current->count; + count = half_open->count; + break; } + item = item->next; } lock->unlock(lock); } @@ -1602,7 +1860,7 @@ METHOD(ike_sa_manager_t, get_half_open_count, u_int, { for (segment = 0; segment < this->segment_count; segment++) { - lock = this->half_open_segments[segment & this->segment_mask].lock; + lock = this->half_open_segments[segment].lock; lock->read_lock(lock); count += this->half_open_segments[segment].count; lock->unlock(lock); @@ -1651,16 +1909,18 @@ METHOD(ike_sa_manager_t, flush, void, while (enumerator->enumerate(enumerator, &entry, &segment)) { charon->bus->set_sa(charon->bus, entry->ike_sa); - /* as the delete never gets processed, fire down events */ - switch (entry->ike_sa->get_state(entry->ike_sa)) - { - case IKE_ESTABLISHED: - case IKE_REKEYING: - case IKE_DELETING: - charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE); - break; - default: - break; + if (entry->ike_sa->get_version(entry->ike_sa) == IKEV2) + { /* as the delete never gets processed, fire down events */ + switch (entry->ike_sa->get_state(entry->ike_sa)) + { + case IKE_ESTABLISHED: + case IKE_REKEYING: + case IKE_DELETING: + charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE); + break; + default: + break; + } } entry->ike_sa->delete(entry->ike_sa); } @@ -1680,6 +1940,10 @@ METHOD(ike_sa_manager_t, flush, void, { remove_connected_peers(this, entry); } + if (entry->init_hash.ptr) + { + remove_init_hash(this, entry->init_hash); + } remove_entry_at((private_enumerator_t*)enumerator); entry_destroy(entry); } @@ -1698,24 +1962,22 @@ METHOD(ike_sa_manager_t, destroy, void, { u_int i; - for (i = 0; i < this->table_size; i++) - { - DESTROY_IF(this->ike_sa_table[i]); - DESTROY_IF(this->half_open_table[i]); - DESTROY_IF(this->connected_peers_table[i]); - } + /* these are already cleared in flush() above */ free(this->ike_sa_table); free(this->half_open_table); free(this->connected_peers_table); + free(this->init_hashes_table); for (i = 0; i < this->segment_count; i++) { this->segments[i].mutex->destroy(this->segments[i].mutex); this->half_open_segments[i].lock->destroy(this->half_open_segments[i].lock); this->connected_peers_segments[i].lock->destroy(this->connected_peers_segments[i].lock); + this->init_hashes_segments[i].mutex->destroy(this->init_hashes_segments[i].mutex); } free(this->segments); free(this->half_open_segments); free(this->connected_peers_segments); + free(this->init_hashes_segments); free(this); } @@ -1757,6 +2019,7 @@ ike_sa_manager_t *ike_sa_manager_create() .check_uniqueness = _check_uniqueness, .has_contact = _has_contact, .create_enumerator = _create_enumerator, + .create_id_enumerator = _create_id_enumerator, .checkin = _checkin, .checkin_and_destroy = _checkin_and_destroy, .get_count = _get_count, @@ -1782,17 +2045,19 @@ ike_sa_manager_t *ike_sa_manager_create() return NULL; } - this->table_size = get_nearest_powerof2(lib->settings->get_int(lib->settings, - "charon.ikesa_table_size", DEFAULT_HASHTABLE_SIZE)); + this->table_size = get_nearest_powerof2(lib->settings->get_int( + lib->settings, "%s.ikesa_table_size", + DEFAULT_HASHTABLE_SIZE, charon->name)); this->table_size = max(1, min(this->table_size, MAX_HASHTABLE_SIZE)); this->table_mask = this->table_size - 1; - this->segment_count = get_nearest_powerof2(lib->settings->get_int(lib->settings, - "charon.ikesa_table_segments", DEFAULT_SEGMENT_COUNT)); + this->segment_count = get_nearest_powerof2(lib->settings->get_int( + lib->settings, "%s.ikesa_table_segments", + DEFAULT_SEGMENT_COUNT, charon->name)); this->segment_count = max(1, min(this->segment_count, this->table_size)); this->segment_mask = this->segment_count - 1; - this->ike_sa_table = calloc(this->table_size, sizeof(linked_list_t*)); + this->ike_sa_table = calloc(this->table_size, sizeof(table_item_t*)); this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t)); for (i = 0; i < this->segment_count; i++) { @@ -1801,7 +2066,7 @@ ike_sa_manager_t *ike_sa_manager_create() } /* we use the same table parameters for the table to track half-open SAs */ - this->half_open_table = calloc(this->table_size, sizeof(linked_list_t*)); + this->half_open_table = calloc(this->table_size, sizeof(table_item_t*)); this->half_open_segments = calloc(this->segment_count, sizeof(shareable_segment_t)); for (i = 0; i < this->segment_count; i++) { @@ -1810,7 +2075,7 @@ ike_sa_manager_t *ike_sa_manager_create() } /* also for the hash table used for duplicate tests */ - this->connected_peers_table = calloc(this->table_size, sizeof(linked_list_t*)); + this->connected_peers_table = calloc(this->table_size, sizeof(table_item_t*)); this->connected_peers_segments = calloc(this->segment_count, sizeof(shareable_segment_t)); for (i = 0; i < this->segment_count; i++) { @@ -1818,7 +2083,16 @@ ike_sa_manager_t *ike_sa_manager_create() this->connected_peers_segments[i].count = 0; } + /* and again for the table of hashes of seen initial IKE messages */ + this->init_hashes_table = calloc(this->table_size, sizeof(table_item_t*)); + this->init_hashes_segments = calloc(this->segment_count, sizeof(segment_t)); + for (i = 0; i < this->segment_count; i++) + { + this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE); + this->init_hashes_segments[i].count = 0; + } + this->reuse_ikesa = lib->settings->get_bool(lib->settings, - "charon.reuse_ikesa", TRUE); + "%s.reuse_ikesa", TRUE, charon->name); return &this->public; } diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 5e542e7df..a68ae7763 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -52,10 +52,12 @@ struct ike_sa_manager_t { /** * Create and check out a new IKE_SA. * + * @param version IKE version of this SA * @param initiator TRUE for initiator, FALSE otherwise * @returns created and checked out IKE_SA */ - ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator); + ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, ike_version_t version, + bool initiator); /** * Checkout an IKE_SA by a message. @@ -167,6 +169,20 @@ struct ike_sa_manager_t { */ enumerator_t *(*create_enumerator) (ike_sa_manager_t* this, bool wait); + /** + * Create an enumerator over ike_sa_id_t*, matching peer identities. + * + * The remote peer is identified by its XAuth or EAP identity, if available. + * + * @param me local peer identity to match + * @param other remote peer identity to match + * @param family address family to match, 0 for any + * @return enumerator over ike_sa_id_t* + */ + enumerator_t* (*create_id_enumerator)(ike_sa_manager_t *this, + identification_t *me, identification_t *other, + int family); + /** * Checkin the SA after usage. * diff --git a/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c new file mode 100644 index 000000000..689f5f376 --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "hybrid_authenticator.h" + +#include +#include + +typedef struct private_hybrid_authenticator_t private_hybrid_authenticator_t; + +/** + * Private data of an hybrid_authenticator_t object. + */ +struct private_hybrid_authenticator_t { + + /** + * Public authenticator_t interface. + */ + hybrid_authenticator_t public; + + /** + * Public key authenticator + */ + authenticator_t *sig; + + /** + * HASH payload authenticator without credentials + */ + authenticator_t *hash; +}; + +METHOD(authenticator_t, build_i, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->hash->build(this->hash, message); +} + +METHOD(authenticator_t, process_r, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->hash->process(this->hash, message); +} + +METHOD(authenticator_t, build_r, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->sig->build(this->sig, message); +} + +METHOD(authenticator_t, process_i, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->sig->process(this->sig, message); +} + +METHOD(authenticator_t, destroy, void, + private_hybrid_authenticator_t *this) +{ + DESTROY_IF(this->hash); + DESTROY_IF(this->sig); + free(this); +} + +/* + * Described in header. + */ +hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) +{ + private_hybrid_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .hash = (authenticator_t*)psk_v1_authenticator_create(ike_sa, initiator, + dh, dh_value, sa_payload, id_payload, TRUE), + .sig = authenticator_create_v1(ike_sa, initiator, AUTH_RSA, dh, + dh_value, sa_payload, chunk_clone(id_payload)), + ); + if (!this->sig || !this->hash) + { + destroy(this); + return NULL; + } + if (initiator) + { + this->public.authenticator.build = _build_i; + this->public.authenticator.process = _process_i; + } + else + { + this->public.authenticator.build = _build_r; + this->public.authenticator.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h new file mode 100644 index 000000000..69e596959 --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hybrid_authenticator hybrid_authenticator + * @{ @ingroup authenticators_v1 + */ + +#ifndef HYBRID_AUTHENTICATOR_H_ +#define HYBRID_AUTHENTICATOR_H_ + +typedef struct hybrid_authenticator_t hybrid_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using IKEv1 hybrid authentication. + */ +struct hybrid_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build hybrid signatures. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) + * @return hybrid authenticator + */ +hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); + +#endif /** HYBRID_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c new file mode 100644 index 000000000..ee15408c7 --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "psk_v1_authenticator.h" + +#include +#include +#include + +typedef struct private_psk_v1_authenticator_t private_psk_v1_authenticator_t; + +/** + * Private data of an psk_v1_authenticator_t object. + */ +struct private_psk_v1_authenticator_t { + + /** + * Public authenticator_t interface. + */ + psk_v1_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * TRUE if we are initiator + */ + bool initiator; + + /** + * DH key exchange + */ + diffie_hellman_t *dh; + + /** + * Others DH public value + */ + chunk_t dh_value; + + /** + * Encoded SA payload, without fixed header + */ + chunk_t sa_payload; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_payload; + + /** + * Used for Hybrid authentication to build hash without PSK? + */ + bool hybrid; +}; + +METHOD(authenticator_t, build, status_t, + private_psk_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *hash_payload; + keymat_v1_t *keymat; + chunk_t hash, dh; + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_hash(keymat, this->initiator, dh, this->dh_value, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload, &hash)) + { + free(dh.ptr); + return FAILED; + } + free(dh.ptr); + + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + message->add_payload(message, &hash_payload->payload_interface); + free(hash.ptr); + + return SUCCESS; +} + +METHOD(authenticator_t, process, status_t, + private_psk_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *hash_payload; + keymat_v1_t *keymat; + chunk_t hash, dh; + auth_cfg_t *auth; + + hash_payload = (hash_payload_t*)message->get_payload(message, HASH_V1); + if (!hash_payload) + { + DBG1(DBG_IKE, "HASH payload missing in message"); + return FAILED; + } + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload, &hash)) + { + free(dh.ptr); + return FAILED; + } + free(dh.ptr); + if (chunk_equals(hash, hash_payload->get_hash(hash_payload))) + { + free(hash.ptr); + if (!this->hybrid) + { + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + } + return SUCCESS; + } + free(hash.ptr); + DBG1(DBG_IKE, "calculated HASH does not match HASH payload"); + return FAILED; +} + +METHOD(authenticator_t, destroy, void, + private_psk_v1_authenticator_t *this) +{ + chunk_free(&this->id_payload); + free(this); +} + +/* + * Described in header. + */ +psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload, bool hybrid) +{ + private_psk_v1_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh = dh, + .dh_value = dh_value, + .sa_payload = sa_payload, + .id_payload = id_payload, + .hybrid = hybrid, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h new file mode 100644 index 000000000..cc9e18ba1 --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup psk_v1_authenticator psk_v1_authenticator + * @{ @ingroup authenticators_v1 + */ + +#ifndef PSK_V1_AUTHENTICATOR_H_ +#define PSK_V1_AUTHENTICATOR_H_ + +typedef struct psk_v1_authenticator_t psk_v1_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using pre-shared keys for IKEv1. + */ +struct psk_v1_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build PSK signatures. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) + * @param hybrid TRUE if used for hybrid authentication without PSK + * @return PSK authenticator + */ +psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload, bool hybrid); + +#endif /** PSK_V1_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c new file mode 100644 index 000000000..d81c77f0d --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pubkey_v1_authenticator.h" + +#include +#include +#include + +typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t; + +/** + * Private data of an pubkey_v1_authenticator_t object. + */ +struct private_pubkey_v1_authenticator_t { + + /** + * Public authenticator_t interface. + */ + pubkey_v1_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * TRUE if we are initiator + */ + bool initiator; + + /** + * DH key exchange + */ + diffie_hellman_t *dh; + + /** + * Others DH public value + */ + chunk_t dh_value; + + /** + * Encoded SA payload, without fixed header + */ + chunk_t sa_payload; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_payload; + + /** + * Key type to use + */ + key_type_t type; +}; + +METHOD(authenticator_t, build, status_t, + private_pubkey_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *sig_payload; + chunk_t hash, sig, dh; + keymat_v1_t *keymat; + status_t status; + private_key_t *private; + identification_t *id; + auth_cfg_t *auth; + signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL; + + if (this->type == KEY_ECDSA) + { + scheme = SIGN_ECDSA_WITH_NULL; + } + + id = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + private = lib->credmgr->get_private(lib->credmgr, this->type, id, auth); + if (!private) + { + DBG1(DBG_IKE, "no %N private key found for '%Y'", + key_type_names, this->type, id); + return NOT_FOUND; + } + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_hash(keymat, this->initiator, dh, this->dh_value, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload, &hash)) + { + private->destroy(private); + free(dh.ptr); + return FAILED; + } + free(dh.ptr); + + if (private->sign(private, scheme, hash, &sig)) + { + sig_payload = hash_payload_create(SIGNATURE_V1); + sig_payload->set_hash(sig_payload, sig); + free(sig.ptr); + message->add_payload(message, &sig_payload->payload_interface); + status = SUCCESS; + DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id); + } + else + { + DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id); + status = FAILED; + } + private->destroy(private); + free(hash.ptr); + + return status; +} + +METHOD(authenticator_t, process, status_t, + private_pubkey_v1_authenticator_t *this, message_t *message) +{ + chunk_t hash, sig, dh; + keymat_v1_t *keymat; + public_key_t *public; + hash_payload_t *sig_payload; + auth_cfg_t *auth, *current_auth; + enumerator_t *enumerator; + status_t status = NOT_FOUND; + identification_t *id; + signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL; + + if (this->type == KEY_ECDSA) + { + scheme = SIGN_ECDSA_WITH_NULL; + } + + sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1); + if (!sig_payload) + { + DBG1(DBG_IKE, "SIG payload missing in message"); + return FAILED; + } + + id = this->ike_sa->get_other_id(this->ike_sa); + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload, &hash)) + { + free(dh.ptr); + return FAILED; + } + free(dh.ptr); + + sig = sig_payload->get_hash(sig_payload); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, this->type, + id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) + { + if (public->verify(public, scheme, hash, sig)) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + id, key_type_names, this->type); + status = SUCCESS; + auth->merge(auth, current_auth, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + break; + } + else + { + DBG1(DBG_IKE, "signature validation failed, looking for another key"); + status = FAILED; + } + } + enumerator->destroy(enumerator); + free(hash.ptr); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", + key_type_names, this->type, id); + } + return status; +} + +METHOD(authenticator_t, destroy, void, + private_pubkey_v1_authenticator_t *this) +{ + chunk_free(&this->id_payload); + free(this); +} + +/* + * Described in header. + */ +pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload, key_type_t type) +{ + private_pubkey_v1_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh = dh, + .dh_value = dh_value, + .sa_payload = sa_payload, + .id_payload = id_payload, + .type = type, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h new file mode 100644 index 000000000..385664cf3 --- /dev/null +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pubkey_v1_authenticator pubkey_v1_authenticator + * @{ @ingroup authenticators_v1 + */ + +#ifndef PUBKEY_V1_AUTHENTICATOR_H_ +#define PUBKEY_V1_AUTHENTICATOR_H_ + +typedef struct pubkey_v1_authenticator_t pubkey_v1_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using public keys for IKEv1. + */ +struct pubkey_v1_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build and verify public key signatures. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are IKE_SA initiator + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) + * @param type key type to use, KEY_RSA or KEY_ECDSA + * @return pubkey authenticator + */ +pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload, key_type_t type); + +#endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c new file mode 100644 index 000000000..cff344a34 --- /dev/null +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -0,0 +1,1157 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "keymat_v1.h" + +#include +#include +#include +#include + +typedef struct private_keymat_v1_t private_keymat_v1_t; + +/** + * Max. number of IVs to track. + */ +#define MAX_IV 3 + +/** + * Max. number of Quick Modes to track. + */ +#define MAX_QM 2 + +/** + * Data stored for IVs + */ +typedef struct { + /** message ID */ + u_int32_t mid; + /** current IV */ + chunk_t iv; + /** last block of encrypted message */ + chunk_t last_block; +} iv_data_t; + +/** + * Private data of an keymat_t object. + */ +struct private_keymat_v1_t { + + /** + * Public keymat_v1_t interface. + */ + keymat_v1_t public; + + /** + * IKE_SA Role, initiator or responder + */ + bool initiator; + + /** + * General purpose PRF + */ + prf_t *prf; + + /** + * PRF to create Phase 1 HASH payloads + */ + prf_t *prf_auth; + + /** + * Crypter wrapped in an aead_t interface + */ + aead_t *aead; + + /** + * Hasher used for IV generation (and other things like e.g. NAT-T) + */ + hasher_t *hasher; + + /** + * Key used for authentication during main mode + */ + chunk_t skeyid; + + /** + * Key to derive key material from for non-ISAKMP SAs, rekeying + */ + chunk_t skeyid_d; + + /** + * Key used for authentication after main mode + */ + chunk_t skeyid_a; + + /** + * Phase 1 IV + */ + iv_data_t phase1_iv; + + /** + * Keep track of IVs for exchanges after phase 1. We store only a limited + * number of IVs in an MRU sort of way. Stores iv_data_t objects. + */ + linked_list_t *ivs; + + /** + * Keep track of Nonces during Quick Mode exchanges. Only a limited number + * of QMs are tracked at the same time. Stores qm_data_t objects. + */ + linked_list_t *qms; +}; + + +/** + * Destroy an iv_data_t object. + */ +static void iv_data_destroy(iv_data_t *this) +{ + chunk_free(&this->last_block); + chunk_free(&this->iv); + free(this); +} + +/** + * Data stored for Quick Mode exchanges + */ +typedef struct { + /** message ID */ + u_int32_t mid; + /** Ni_b (Nonce from first message) */ + chunk_t n_i; + /** Nr_b (Nonce from second message) */ + chunk_t n_r; +} qm_data_t; + +/** + * Destroy a qm_data_t object. + */ +static void qm_data_destroy(qm_data_t *this) +{ + chunk_free(&this->n_i); + chunk_free(&this->n_r); + free(this); +} + +/** + * Constants used in key derivation. + */ +static const chunk_t octet_0 = chunk_from_chars(0x00); +static const chunk_t octet_1 = chunk_from_chars(0x01); +static const chunk_t octet_2 = chunk_from_chars(0x02); + +/** + * Simple aead_t implementation without support for authentication. + */ +typedef struct { + /** implements aead_t interface */ + aead_t aead; + /** crypter to be used */ + crypter_t *crypter; +} private_aead_t; + + +METHOD(aead_t, encrypt, bool, + private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, + chunk_t *encrypted) +{ + return this->crypter->encrypt(this->crypter, plain, iv, encrypted); +} + +METHOD(aead_t, decrypt, bool, + private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv, + chunk_t *plain) +{ + return this->crypter->decrypt(this->crypter, encrypted, iv, plain); +} + +METHOD(aead_t, get_block_size, size_t, + private_aead_t *this) +{ + return this->crypter->get_block_size(this->crypter); +} + +METHOD(aead_t, get_icv_size, size_t, + private_aead_t *this) +{ + return 0; +} + +METHOD(aead_t, get_iv_size, size_t, + private_aead_t *this) +{ + /* in order to create the messages properly we return 0 here */ + return 0; +} + +METHOD(aead_t, get_key_size, size_t, + private_aead_t *this) +{ + return this->crypter->get_key_size(this->crypter); +} + +METHOD(aead_t, set_key, bool, + private_aead_t *this, chunk_t key) +{ + return this->crypter->set_key(this->crypter, key); +} + +METHOD(aead_t, aead_destroy, void, + private_aead_t *this) +{ + this->crypter->destroy(this->crypter); + free(this); +} + +/** + * Expand SKEYID_e according to Appendix B in RFC 2409. + * TODO-IKEv1: verify keys (e.g. for weak keys, see Appendix B) + */ +static bool expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf, + chunk_t *ka) +{ + size_t block_size; + chunk_t seed; + int i; + + if (skeyid_e.len >= key_size) + { /* no expansion required, reduce to key_size */ + skeyid_e.len = key_size; + *ka = skeyid_e; + return TRUE; + } + block_size = prf->get_block_size(prf); + *ka = chunk_alloc((key_size / block_size + 1) * block_size); + ka->len = key_size; + + /* Ka = K1 | K2 | ..., K1 = prf(SKEYID_e, 0), K2 = prf(SKEYID_e, K1) ... */ + if (!prf->set_key(prf, skeyid_e)) + { + chunk_clear(ka); + chunk_clear(&skeyid_e); + return FALSE; + } + seed = octet_0; + for (i = 0; i < key_size; i += block_size) + { + if (!prf->get_bytes(prf, seed, ka->ptr + i)) + { + chunk_clear(ka); + chunk_clear(&skeyid_e); + return FALSE; + } + seed = chunk_create(ka->ptr + i, block_size); + } + chunk_clear(&skeyid_e); + return TRUE; +} + +/** + * Create a simple implementation of the aead_t interface which only encrypts + * or decrypts data. + */ +static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e) +{ + private_aead_t *this; + u_int16_t alg, key_size; + crypter_t *crypter; + chunk_t ka; + + if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, + &key_size)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, ENCRYPTION_ALGORITHM); + return NULL; + } + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + if (!crypter) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, alg, key_size); + return NULL; + } + key_size = crypter->get_key_size(crypter); + if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, &ka)) + { + return NULL; + } + DBG4(DBG_IKE, "encryption key Ka %B", &ka); + if (!crypter->set_key(crypter, ka)) + { + chunk_clear(&ka); + return NULL; + } + chunk_clear(&ka); + + INIT(this, + .aead = { + .encrypt = _encrypt, + .decrypt = _decrypt, + .get_block_size = _get_block_size, + .get_icv_size = _get_icv_size, + .get_iv_size = _get_iv_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _aead_destroy, + }, + .crypter = crypter, + ); + return &this->aead; +} + +/** + * Converts integrity algorithm to PRF algorithm + */ +static u_int16_t auth_to_prf(u_int16_t alg) +{ + switch (alg) + { + case AUTH_HMAC_SHA1_96: + return PRF_HMAC_SHA1; + case AUTH_HMAC_SHA2_256_128: + return PRF_HMAC_SHA2_256; + case AUTH_HMAC_SHA2_384_192: + return PRF_HMAC_SHA2_384; + case AUTH_HMAC_SHA2_512_256: + return PRF_HMAC_SHA2_512; + case AUTH_HMAC_MD5_96: + return PRF_HMAC_MD5; + case AUTH_AES_XCBC_96: + return PRF_AES128_XCBC; + default: + return PRF_UNDEFINED; + } +} + +/** + * Converts integrity algorithm to hash algorithm + */ +static u_int16_t auth_to_hash(u_int16_t alg) +{ + switch (alg) + { + case AUTH_HMAC_SHA1_96: + return HASH_SHA1; + case AUTH_HMAC_SHA2_256_128: + return HASH_SHA256; + case AUTH_HMAC_SHA2_384_192: + return HASH_SHA384; + case AUTH_HMAC_SHA2_512_256: + return HASH_SHA512; + case AUTH_HMAC_MD5_96: + return HASH_MD5; + default: + return HASH_UNKNOWN; + } +} + +/** + * Adjust the key length for PRF algorithms that expect a fixed key length. + */ +static void adjust_keylen(u_int16_t alg, chunk_t *key) +{ + switch (alg) + { + case PRF_AES128_XCBC: + /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does + * not and therefore fixed key semantics apply to XCBC for key + * derivation. */ + key->len = min(key->len, 16); + break; + default: + /* all other algorithms use variable key length */ + break; + } +} + +METHOD(keymat_v1_t, derive_ike_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + auth_method_t auth, shared_key_t *shared_key) +{ + chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e; + chunk_t skeyid; + u_int16_t alg; + + spi_i = chunk_alloca(sizeof(u_int64_t)); + spi_r = chunk_alloca(sizeof(u_int64_t)); + + if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { /* no PRF negotiated, use HMAC version of integrity algorithm instead */ + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) + || (alg = auth_to_prf(alg)) == PRF_UNDEFINED) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, PSEUDO_RANDOM_FUNCTION); + return FALSE; + } + } + this->prf = lib->crypto->create_prf(lib->crypto, alg); + if (!this->prf) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + if (this->prf->get_block_size(this->prf) < + this->prf->get_key_size(this->prf)) + { /* TODO-IKEv1: support PRF output expansion (RFC 2409, Appendix B) */ + DBG1(DBG_IKE, "expansion of %N %N output not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + + if (dh->get_shared_secret(dh, &g_xy) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &g_xy); + + *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id); + *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id); + nonces = chunk_cata("cc", nonce_i, nonce_r); + + switch (auth) + { + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + { /* SKEYID = prf(pre-shared-key, Ni_b | Nr_b) */ + chunk_t psk; + if (!shared_key) + { + chunk_clear(&g_xy); + return FALSE; + } + psk = shared_key->get_key(shared_key); + adjust_keylen(alg, &psk); + if (!this->prf->set_key(this->prf, psk) || + !this->prf->allocate_bytes(this->prf, nonces, &skeyid)) + { + chunk_clear(&g_xy); + return FALSE; + } + break; + } + case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + { + if (!this->prf->set_key(this->prf, nonces) || + !this->prf->allocate_bytes(this->prf, g_xy, &skeyid)) + { + chunk_clear(&g_xy); + return FALSE; + } + break; + } + default: + /* TODO-IKEv1: implement key derivation for other schemes */ + /* authentication class not supported */ + chunk_clear(&g_xy); + return FALSE; + } + adjust_keylen(alg, &skeyid); + DBG4(DBG_IKE, "SKEYID %B", &skeyid); + + /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ + data = chunk_cat("cccc", g_xy, spi_i, spi_r, octet_0); + if (!this->prf->set_key(this->prf, skeyid) || + !this->prf->allocate_bytes(this->prf, data, &this->skeyid_d)) + { + chunk_clear(&g_xy); + chunk_clear(&data); + return FALSE; + } + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_d %B", &this->skeyid_d); + + /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ + data = chunk_cat("ccccc", this->skeyid_d, g_xy, spi_i, spi_r, octet_1); + if (!this->prf->allocate_bytes(this->prf, data, &this->skeyid_a)) + { + chunk_clear(&g_xy); + chunk_clear(&data); + return FALSE; + } + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_a %B", &this->skeyid_a); + + /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ + data = chunk_cat("ccccc", this->skeyid_a, g_xy, spi_i, spi_r, octet_2); + if (!this->prf->allocate_bytes(this->prf, data, &skeyid_e)) + { + chunk_clear(&g_xy); + chunk_clear(&data); + return FALSE; + } + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_e %B", &skeyid_e); + + chunk_clear(&g_xy); + + switch (auth) + { + case AUTH_ECDSA_256: + alg = PRF_HMAC_SHA2_256; + break; + case AUTH_ECDSA_384: + alg = PRF_HMAC_SHA2_384; + break; + case AUTH_ECDSA_521: + alg = PRF_HMAC_SHA2_512; + break; + default: + /* use proposal algorithm */ + break; + } + this->prf_auth = lib->crypto->create_prf(lib->crypto, alg); + if (!this->prf_auth) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + chunk_clear(&skeyid); + return FALSE; + } + if (!this->prf_auth->set_key(this->prf_auth, skeyid)) + { + chunk_clear(&skeyid); + return FALSE; + } + chunk_clear(&skeyid); + + this->aead = create_aead(proposal, this->prf, skeyid_e); + if (!this->aead) + { + return FALSE; + } + if (!this->hasher && !this->public.create_hasher(&this->public, proposal)) + { + return FALSE; + } + + dh->get_my_public_value(dh, &dh_me); + g_xi = this->initiator ? dh_me : dh_other; + g_xr = this->initiator ? dh_other : dh_me; + + /* initial IV = hash(g^xi | g^xr) */ + data = chunk_cata("cc", g_xi, g_xr); + chunk_free(&dh_me); + if (!this->hasher->allocate_hash(this->hasher, data, &this->phase1_iv.iv)) + { + return FALSE; + } + if (this->phase1_iv.iv.len > this->aead->get_block_size(this->aead)) + { + this->phase1_iv.iv.len = this->aead->get_block_size(this->aead); + } + DBG4(DBG_IKE, "initial IV %B", &this->phase1_iv.iv); + + return TRUE; +} + +METHOD(keymat_v1_t, derive_child_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + u_int32_t spi_i, u_int32_t spi_r, chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r) +{ + u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; + u_int8_t protocol; + prf_plus_t *prf_plus; + chunk_t seed, secret = chunk_empty; + bool success = FALSE; + + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &enc_alg, &enc_size)) + { + DBG2(DBG_CHD, " using %N for encryption", + encryption_algorithm_names, enc_alg); + + if (!enc_size) + { + enc_size = keymat_get_keylen_encr(enc_alg); + } + if (enc_alg != ENCR_NULL && !enc_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + encryption_algorithm_names, enc_alg); + return FALSE; + } + /* to bytes */ + enc_size /= 8; + + /* CCM/GCM/CTR/GMAC needs additional bytes */ + switch (enc_alg) + { + case ENCR_AES_CCM_ICV8: + case ENCR_AES_CCM_ICV12: + case ENCR_AES_CCM_ICV16: + case ENCR_CAMELLIA_CCM_ICV8: + case ENCR_CAMELLIA_CCM_ICV12: + case ENCR_CAMELLIA_CCM_ICV16: + enc_size += 3; + break; + case ENCR_AES_GCM_ICV8: + case ENCR_AES_GCM_ICV12: + case ENCR_AES_GCM_ICV16: + case ENCR_AES_CTR: + case ENCR_NULL_AUTH_AES_GMAC: + enc_size += 4; + break; + default: + break; + } + } + + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, &int_size)) + { + DBG2(DBG_CHD, " using %N for integrity", + integrity_algorithm_names, int_alg); + + if (!int_size) + { + int_size = keymat_get_keylen_integ(int_alg); + } + if (!int_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + integrity_algorithm_names, int_alg); + return FALSE; + } + /* to bytes */ + int_size /= 8; + } + + /* KEYMAT = prf+(SKEYID_d, [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b) */ + if (!this->prf->set_key(this->prf, this->skeyid_d)) + { + return FALSE; + } + protocol = proposal->get_protocol(proposal); + if (dh) + { + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_CHD, "DH secret %B", &secret); + } + + *encr_r = *integ_r = *encr_i = *integ_i = chunk_empty; + seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol), + chunk_from_thing(spi_r), nonce_i, nonce_r); + DBG4(DBG_CHD, "initiator SA seed %B", &seed); + + prf_plus = prf_plus_create(this->prf, FALSE, seed); + if (!prf_plus || + !prf_plus->allocate_bytes(prf_plus, enc_size, encr_i) || + !prf_plus->allocate_bytes(prf_plus, int_size, integ_i)) + { + goto failure; + } + + seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol), + chunk_from_thing(spi_i), nonce_i, nonce_r); + DBG4(DBG_CHD, "responder SA seed %B", &seed); + prf_plus->destroy(prf_plus); + prf_plus = prf_plus_create(this->prf, FALSE, seed); + if (!prf_plus || + !prf_plus->allocate_bytes(prf_plus, enc_size, encr_r) || + !prf_plus->allocate_bytes(prf_plus, int_size, integ_r)) + { + goto failure; + } + + if (enc_size) + { + DBG4(DBG_CHD, "encryption initiator key %B", encr_i); + DBG4(DBG_CHD, "encryption responder key %B", encr_r); + } + if (int_size) + { + DBG4(DBG_CHD, "integrity initiator key %B", integ_i); + DBG4(DBG_CHD, "integrity responder key %B", integ_r); + } + success = TRUE; + +failure: + if (!success) + { + chunk_clear(encr_i); + chunk_clear(integ_i); + chunk_clear(encr_r); + chunk_clear(integ_r); + } + DESTROY_IF(prf_plus); + chunk_clear(&secret); + + return success; +} + +METHOD(keymat_v1_t, create_hasher, bool, + private_keymat_v1_t *this, proposal_t *proposal) +{ + u_int16_t alg; + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) || + (alg = auth_to_hash(alg)) == HASH_UNKNOWN) + { + DBG1(DBG_IKE, "no %N selected", transform_type_names, HASH_ALGORITHM); + return FALSE; + } + this->hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (!this->hasher) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, HASH_ALGORITHM, + hash_algorithm_names, alg); + return FALSE; + } + return TRUE; +} + +METHOD(keymat_v1_t, get_hasher, hasher_t*, + private_keymat_v1_t *this) +{ + return this->hasher; +} + +METHOD(keymat_v1_t, get_hash, bool, + private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, + ike_sa_id_t *ike_sa_id, chunk_t sa_i, chunk_t id, chunk_t *hash) +{ + chunk_t data; + u_int64_t spi, spi_other; + + /* HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) + * HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) + */ + if (initiator) + { + spi = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_other = ike_sa_id->get_responder_spi(ike_sa_id); + } + else + { + spi_other = ike_sa_id->get_initiator_spi(ike_sa_id); + spi = ike_sa_id->get_responder_spi(ike_sa_id); + } + data = chunk_cat("cccccc", dh, dh_other, + chunk_from_thing(spi), chunk_from_thing(spi_other), + sa_i, id); + + DBG3(DBG_IKE, "HASH_%c data %B", initiator ? 'I' : 'R', &data); + + if (!this->prf_auth->allocate_bytes(this->prf_auth, data, hash)) + { + free(data.ptr); + return FALSE; + } + + DBG3(DBG_IKE, "HASH_%c %B", initiator ? 'I' : 'R', hash); + + free(data.ptr); + return TRUE; +} + +/** + * Get the nonce value found in the given message. + * Returns FALSE if none is found. + */ +static bool get_nonce(message_t *message, chunk_t *n) +{ + nonce_payload_t *nonce; + nonce = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (nonce) + { + *n = nonce->get_nonce(nonce); + return TRUE; + } + return FALSE; +} + +/** + * Generate the message data in order to generate the hashes. + */ +static chunk_t get_message_data(message_t *message, generator_t *generator) +{ + payload_t *payload, *next; + enumerator_t *enumerator; + u_int32_t *lenpos; + + if (message->is_encoded(message)) + { /* inbound, although the message is generated, we cannot access the + * cleartext message data, so generate it anyway */ + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == HASH_V1) + { + continue; + } + generator->generate_payload(generator, payload); + } + enumerator->destroy(enumerator); + } + else + { + /* outbound, generate the payloads (there is no HASH payload yet) */ + enumerator = message->create_payload_enumerator(message); + if (enumerator->enumerate(enumerator, &payload)) + { + while (enumerator->enumerate(enumerator, &next)) + { + payload->set_next_type(payload, next->get_type(next)); + generator->generate_payload(generator, payload); + payload = next; + } + payload->set_next_type(payload, NO_PAYLOAD); + generator->generate_payload(generator, payload); + } + enumerator->destroy(enumerator); + } + return generator->get_chunk(generator, &lenpos); +} + +/** + * Try to find data about a Quick Mode with the given message ID, + * if none is found, state is generated. + */ +static qm_data_t *lookup_quick_mode(private_keymat_v1_t *this, u_int32_t mid) +{ + enumerator_t *enumerator; + qm_data_t *qm, *found = NULL; + + enumerator = this->qms->create_enumerator(this->qms); + while (enumerator->enumerate(enumerator, &qm)) + { + if (qm->mid == mid) + { /* state gets moved to the front of the list */ + this->qms->remove_at(this->qms, enumerator); + found = qm; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + INIT(found, + .mid = mid, + ); + } + this->qms->insert_first(this->qms, found); + /* remove least recently used state if maximum reached */ + if (this->qms->get_count(this->qms) > MAX_QM && + this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS) + { + qm_data_destroy(qm); + } + return found; +} + +METHOD(keymat_v1_t, get_hash_phase2, bool, + private_keymat_v1_t *this, message_t *message, chunk_t *hash) +{ + u_int32_t mid, mid_n; + chunk_t data = chunk_empty; + bool add_message = TRUE; + char *name = "Hash"; + + if (!this->prf) + { /* no keys derived yet */ + return FALSE; + } + + mid = message->get_message_id(message); + mid_n = htonl(mid); + + /* Hashes are simple for most exchanges in Phase 2: + * Hash = prf(SKEYID_a, M-ID | Complete message after HASH payload) + * For Quick Mode there are three hashes: + * Hash(1) = same as above + * Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH payload) + * Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + * So, for Quick Mode we keep track of the nonce values. + */ + switch (message->get_exchange_type(message)) + { + case QUICK_MODE: + { + qm_data_t *qm = lookup_quick_mode(this, mid); + if (!qm->n_i.ptr) + { /* Hash(1) = prf(SKEYID_a, M-ID | Message after HASH payload) */ + name = "Hash(1)"; + if (!get_nonce(message, &qm->n_i)) + { + return FALSE; + } + data = chunk_from_thing(mid_n); + } + else if (!qm->n_r.ptr) + { /* Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH) */ + name = "Hash(2)"; + if (!get_nonce(message, &qm->n_r)) + { + return FALSE; + } + data = chunk_cata("cc", chunk_from_thing(mid_n), qm->n_i); + } + else + { /* Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + name = "Hash(3)"; + data = chunk_cata("cccc", octet_0, chunk_from_thing(mid_n), + qm->n_i, qm->n_r); + add_message = FALSE; + /* we don't need the state anymore */ + this->qms->remove(this->qms, qm, NULL); + qm_data_destroy(qm); + } + break; + } + case TRANSACTION: + case INFORMATIONAL_V1: + /* Hash = prf(SKEYID_a, M-ID | Message after HASH payload) */ + data = chunk_from_thing(mid_n); + break; + default: + return FALSE; + } + if (!this->prf->set_key(this->prf, this->skeyid_a)) + { + return FALSE; + } + if (add_message) + { + generator_t *generator; + chunk_t msg; + + generator = generator_create_no_dbg(); + msg = get_message_data(message, generator); + if (!this->prf->allocate_bytes(this->prf, data, NULL) || + !this->prf->allocate_bytes(this->prf, msg, hash)) + { + generator->destroy(generator); + return FALSE; + } + generator->destroy(generator); + } + else + { + if (!this->prf->allocate_bytes(this->prf, data, hash)) + { + return FALSE; + } + } + DBG3(DBG_IKE, "%s %B", name, hash); + return TRUE; +} + +/** + * Generate an IV + */ +static bool generate_iv(private_keymat_v1_t *this, iv_data_t *iv) +{ + if (iv->mid == 0 || iv->iv.ptr) + { /* use last block of previous encrypted message */ + chunk_free(&iv->iv); + iv->iv = iv->last_block; + iv->last_block = chunk_empty; + } + else + { + /* initial phase 2 IV = hash(last_phase1_block | mid) */ + u_int32_t net;; + chunk_t data; + + net = htonl(iv->mid); + data = chunk_cata("cc", this->phase1_iv.iv, chunk_from_thing(net)); + if (!this->hasher->allocate_hash(this->hasher, data, &iv->iv)) + { + return FALSE; + } + if (iv->iv.len > this->aead->get_block_size(this->aead)) + { + iv->iv.len = this->aead->get_block_size(this->aead); + } + } + DBG4(DBG_IKE, "next IV for MID %u %B", iv->mid, &iv->iv); + return TRUE; +} + +/** + * Try to find an IV for the given message ID, if not found, generate it. + */ +static iv_data_t *lookup_iv(private_keymat_v1_t *this, u_int32_t mid) +{ + enumerator_t *enumerator; + iv_data_t *iv, *found = NULL; + + if (mid == 0) + { + return &this->phase1_iv; + } + + enumerator = this->ivs->create_enumerator(this->ivs); + while (enumerator->enumerate(enumerator, &iv)) + { + if (iv->mid == mid) + { /* IV gets moved to the front of the list */ + this->ivs->remove_at(this->ivs, enumerator); + found = iv; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + INIT(found, + .mid = mid, + ); + if (!generate_iv(this, found)) + { + iv_data_destroy(found); + return NULL; + } + } + this->ivs->insert_first(this->ivs, found); + /* remove least recently used IV if maximum reached */ + if (this->ivs->get_count(this->ivs) > MAX_IV && + this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS) + { + iv_data_destroy(iv); + } + return found; +} + +METHOD(keymat_v1_t, get_iv, bool, + private_keymat_v1_t *this, u_int32_t mid, chunk_t *out) +{ + iv_data_t *iv; + + iv = lookup_iv(this, mid); + if (iv) + { + *out = iv->iv; + return TRUE; + } + return FALSE; +} + +METHOD(keymat_v1_t, update_iv, bool, + private_keymat_v1_t *this, u_int32_t mid, chunk_t last_block) +{ + iv_data_t *iv = lookup_iv(this, mid); + if (iv) + { /* update last block */ + chunk_free(&iv->last_block); + iv->last_block = chunk_clone(last_block); + return TRUE; + } + return FALSE; +} + +METHOD(keymat_v1_t, confirm_iv, bool, + private_keymat_v1_t *this, u_int32_t mid) +{ + iv_data_t *iv = lookup_iv(this, mid); + if (iv) + { + return generate_iv(this, iv); + } + return FALSE; +} + +METHOD(keymat_t, get_version, ike_version_t, + private_keymat_v1_t *this) +{ + return IKEV1; +} + +METHOD(keymat_t, create_dh, diffie_hellman_t*, + private_keymat_v1_t *this, diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group); +} + +METHOD(keymat_t, create_nonce_gen, nonce_gen_t*, + private_keymat_v1_t *this) +{ + return lib->crypto->create_nonce_gen(lib->crypto); +} + +METHOD(keymat_t, get_aead, aead_t*, + private_keymat_v1_t *this, bool in) +{ + return this->aead; +} + +METHOD(keymat_t, destroy, void, + private_keymat_v1_t *this) +{ + DESTROY_IF(this->prf); + DESTROY_IF(this->prf_auth); + DESTROY_IF(this->aead); + DESTROY_IF(this->hasher); + chunk_clear(&this->skeyid_d); + chunk_clear(&this->skeyid_a); + chunk_free(&this->phase1_iv.iv); + chunk_free(&this->phase1_iv.last_block); + this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy); + this->qms->destroy_function(this->qms, (void*)qm_data_destroy); + free(this); +} + +/** + * See header + */ +keymat_v1_t *keymat_v1_create(bool initiator) +{ + private_keymat_v1_t *this; + + INIT(this, + .public = { + .keymat = { + .get_version = _get_version, + .create_dh = _create_dh, + .create_nonce_gen = _create_nonce_gen, + .get_aead = _get_aead, + .destroy = _destroy, + }, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .create_hasher = _create_hasher, + .get_hasher = _get_hasher, + .get_hash = _get_hash, + .get_hash_phase2 = _get_hash_phase2, + .get_iv = _get_iv, + .update_iv = _update_iv, + .confirm_iv = _confirm_iv, + }, + .ivs = linked_list_create(), + .qms = linked_list_create(), + .initiator = initiator, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/keymat_v1.h b/src/libcharon/sa/ikev1/keymat_v1.h new file mode 100644 index 000000000..cc9f3b339 --- /dev/null +++ b/src/libcharon/sa/ikev1/keymat_v1.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup keymat_v1 keymat_v1 + * @{ @ingroup ikev1 + */ + +#ifndef KEYMAT_V1_H_ +#define KEYMAT_V1_H_ + +#include +#include + +typedef struct keymat_v1_t keymat_v1_t; + +/** + * Derivation and management of sensitive keying material, IKEv1 variant. + */ +struct keymat_v1_t { + + /** + * Implements keymat_t. + */ + keymat_t keymat; + + /** + * Derive keys for the IKE_SA. + * + * These keys are not handed out, but are used by the associated signers, + * crypters and authentication functions. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh() + * @param dh_other public DH value from other peer + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param id IKE_SA identifier + * @param auth authentication method + * @param shared_key PSK in case of AUTH_CLASS_PSK, NULL otherwise + * @return TRUE on success + */ + bool (*derive_ike_keys)(keymat_v1_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t dh_other, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + auth_method_t auth, shared_key_t *shared_key); + + /** + * Derive keys for the CHILD_SA. + * + * @param proposal selected algorithms + * @param dh diffie hellman key, NULL if none used + * @param spi_i SPI chosen by initiatior + * @param spi_r SPI chosen by responder + * @param nonce_i quick mode initiator nonce + * @param nonce_r quick mode responder nonce + * @param encr_i allocated initiators encryption key + * @param integ_i allocated initiators integrity key + * @param encr_r allocated responders encryption key + * @param integ_r allocated responders integrity key + */ + bool (*derive_child_keys)(keymat_v1_t *this, proposal_t *proposal, + diffie_hellman_t *dh, u_int32_t spi_i, u_int32_t spi_r, + chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r); + + /** + * Create the negotiated hasher. + * + * @param proposal selected algorithms + * @return TRUE, if creation was successful + */ + bool (*create_hasher)(keymat_v1_t *this, proposal_t *proposal); + + /** + * Get the negotiated hasher. + * + * @return allocated hasher or NULL + */ + hasher_t *(*get_hasher)(keymat_v1_t *this); + + /** + * Get HASH data for authentication. + * + * @param initiatior TRUE to create HASH_I, FALSE for HASH_R + * @param dh public DH value of peer to create HASH for + * @param dh_other others public DH value + * @param ike_sa_id IKE_SA identifier + * @param sa_i encoded SA payload of initiator + * @param id encoded IDii payload for HASH_I (IDir for HASH_R) + * @param hash chunk receiving allocated HASH data + * @return TRUE if hash allocated successfully + */ + bool (*get_hash)(keymat_v1_t *this, bool initiator, + chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, + chunk_t sa_i, chunk_t id, chunk_t *hash); + + /** + * Get HASH data for integrity/authentication in Phase 2 exchanges. + * + * @param message message to generate the HASH data for + * @param hash chunk receiving allocated hash data + * @return TRUE if hash allocated successfully + */ + bool (*get_hash_phase2)(keymat_v1_t *this, message_t *message, chunk_t *hash); + + /** + * Returns the IV for a message with the given message ID. + * + * The return chunk contains internal data and is valid until the next + * get_iv/udpate_iv/confirm_iv call. + * + * @param mid message ID + * @param iv chunk receiving IV, internal data + * @return TRUE if IV allocated successfully + */ + bool (*get_iv)(keymat_v1_t *this, u_int32_t mid, chunk_t *iv); + + /** + * Updates the IV for the next message with the given message ID. + * + * A call of confirm_iv() is required in order to actually make the IV + * available. This is needed for the inbound case where we store the last + * block of the encrypted message but want to update the IV only after + * verification of the decrypted message. + * + * @param mid message ID + * @param last_block last block of encrypted message (gets cloned) + * @return TRUE if IV updated successfully + */ + bool (*update_iv)(keymat_v1_t *this, u_int32_t mid, chunk_t last_block); + + /** + * Confirms the updated IV for the given message ID. + * + * To actually make the new IV available via get_iv this method has to + * be called after update_iv. + * + * @param mid message ID + * @return TRUE if IV confirmed successfully + */ + bool (*confirm_iv)(keymat_v1_t *this, u_int32_t mid); +}; + +/** + * Create a keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +keymat_v1_t *keymat_v1_create(bool initiator); + +#endif /** KEYMAT_V1_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c new file mode 100644 index 000000000..4096141ec --- /dev/null +++ b/src/libcharon/sa/ikev1/phase1.c @@ -0,0 +1,795 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "phase1.h" + +#include +#include +#include +#include +#include + +typedef struct private_phase1_t private_phase1_t; + +/** + * Private data of an phase1_t object. + */ +struct private_phase1_t { + + /** + * Public phase1_t interface. + */ + phase1_t public; + + /** + * IKE_SA we negotiate + */ + ike_sa_t *ike_sa; + + /** + * Currently selected peer config + */ + peer_cfg_t *peer_cfg; + + /** + * Other possible peer config candidates + */ + linked_list_t *candidates; + + /** + * Acting as initiator + */ + bool initiator; + + /** + * Extracted SA payload bytes + */ + chunk_t sa_payload; + + /** + * DH exchange + */ + diffie_hellman_t *dh; + + /** + * Keymat derivation (from SA) + */ + keymat_v1_t *keymat; + + /** + * Received public DH value from peer + */ + chunk_t dh_value; + + /** + * Initiators nonce + */ + chunk_t nonce_i; + + /** + * Responder nonce + */ + chunk_t nonce_r; +}; + +/** + * Get the first authentcation config from peer config + */ +static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) +{ + enumerator_t *enumerator; + auth_cfg_t *cfg = NULL; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + enumerator->enumerate(enumerator, &cfg); + enumerator->destroy(enumerator); + return cfg; +} + +/** + * Lookup a shared secret for this IKE_SA + */ +static shared_key_t *lookup_shared_key(private_phase1_t *this, + peer_cfg_t *peer_cfg) +{ + host_t *me, *other; + identification_t *my_id, *other_id; + shared_key_t *shared_key = NULL; + auth_cfg_t *my_auth, *other_auth; + enumerator_t *enumerator; + + /* try to get a PSK for IP addresses */ + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = identification_create_from_sockaddr(me->get_sockaddr(me)); + other_id = identification_create_from_sockaddr(other->get_sockaddr(other)); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + } + DESTROY_IF(my_id); + DESTROY_IF(other_id); + if (shared_key) + { + return shared_key; + } + + if (peer_cfg) + { /* as initiator or aggressive responder, use identities */ + my_auth = get_auth_cfg(peer_cfg, TRUE); + other_auth = get_auth_cfg(peer_cfg, FALSE); + if (my_auth && other_auth) + { + my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); + if (peer_cfg->use_aggressive(peer_cfg)) + { + other_id = this->ike_sa->get_other_id(this->ike_sa); + } + else + { + other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); + } + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + if (!shared_key) + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } + } + } + return shared_key; + } + /* as responder, we try to find a config by IP */ + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, NULL, NULL, IKEV1); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + my_auth = get_auth_cfg(peer_cfg, TRUE); + other_auth = get_auth_cfg(peer_cfg, FALSE); + if (my_auth && other_auth) + { + my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); + other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); + if (my_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + if (shared_key) + { + break; + } + else + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } + } + } + } + enumerator->destroy(enumerator); + if (!peer_cfg) + { + DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); + } + return shared_key; +} + +METHOD(phase1_t, create_hasher, bool, + private_phase1_t *this) +{ + return this->keymat->create_hasher(this->keymat, + this->ike_sa->get_proposal(this->ike_sa)); +} + +METHOD(phase1_t, create_dh, bool, + private_phase1_t *this, diffie_hellman_group_t group) +{ + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group); + return this->dh != NULL; +} + +METHOD(phase1_t, derive_keys, bool, + private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method) +{ + shared_key_t *shared_key = NULL; + + switch (method) + { + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + shared_key = lookup_shared_key(this, peer_cfg); + if (!shared_key) + { + return FALSE; + } + break; + default: + break; + } + + if (!this->keymat->derive_ike_keys(this->keymat, + this->ike_sa->get_proposal(this->ike_sa), + this->dh, this->dh_value, this->nonce_i, this->nonce_r, + this->ike_sa->get_id(this->ike_sa), method, shared_key)) + { + DESTROY_IF(shared_key); + DBG1(DBG_IKE, "key derivation for %N failed", auth_method_names, method); + return FALSE; + } + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, this->dh_value, + this->nonce_i, this->nonce_r, NULL, shared_key); + DESTROY_IF(shared_key); + return TRUE; +} + +/** + * Check if a peer skipped authentication by using Hybrid authentication + */ +static bool skipped_auth(private_phase1_t *this, + auth_method_t method, bool local) +{ + bool initiator; + + initiator = local == this->initiator; + if (initiator && method == AUTH_HYBRID_INIT_RSA) + { + return TRUE; + } + if (!initiator && method == AUTH_HYBRID_RESP_RSA) + { + return TRUE; + } + return FALSE; +} + +/** + * Check if remote authentication constraints fulfilled + */ +static bool check_constraints(private_phase1_t *this, auth_method_t method) +{ + identification_t *id; + auth_cfg_t *auth, *cfg; + peer_cfg_t *peer_cfg; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + /* auth identity to comply */ + id = this->ike_sa->get_other_id(this->ike_sa); + auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id)); + if (skipped_auth(this, method, FALSE)) + { + return TRUE; + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + cfg = get_auth_cfg(peer_cfg, FALSE); + return cfg && auth->complies(auth, cfg, TRUE); +} + +/** + * Save authentication information after authentication succeeded + */ +static void save_auth_cfg(private_phase1_t *this, + auth_method_t method, bool local) +{ + auth_cfg_t *auth; + + if (skipped_auth(this, method, local)) + { + return; + } + auth = auth_cfg_create(); + /* for local config, we _copy_ entires from the config, as it contains + * certificates we must send later. */ + auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local); + this->ike_sa->add_auth_cfg(this->ike_sa, local, auth); +} + +/** + * Create an authenticator instance + */ +static authenticator_t* create_authenticator(private_phase1_t *this, + auth_method_t method, chunk_t id) +{ + authenticator_t *authenticator; + + authenticator = authenticator_create_v1(this->ike_sa, this->initiator, + method, this->dh, this->dh_value, this->sa_payload, id); + if (!authenticator) + { + DBG1(DBG_IKE, "negotiated authentication method %N not supported", + auth_method_names, method); + } + return authenticator; +} + +METHOD(phase1_t, verify_auth, bool, + private_phase1_t *this, auth_method_t method, message_t *message, + chunk_t id_data) +{ + authenticator_t *authenticator; + status_t status; + + authenticator = create_authenticator(this, method, id_data); + if (authenticator) + { + status = authenticator->process(authenticator, message); + authenticator->destroy(authenticator); + if (status == SUCCESS && check_constraints(this, method)) + { + save_auth_cfg(this, method, FALSE); + return TRUE; + } + } + return FALSE; +} + +METHOD(phase1_t, build_auth, bool, + private_phase1_t *this, auth_method_t method, message_t *message, + chunk_t id_data) +{ + authenticator_t *authenticator; + status_t status; + + authenticator = create_authenticator(this, method, id_data); + if (authenticator) + { + status = authenticator->build(authenticator, message); + authenticator->destroy(authenticator); + if (status == SUCCESS) + { + save_auth_cfg(this, method, TRUE); + return TRUE; + } + } + return FALSE; +} + +/** + * Get the two auth classes from local or remote config + */ +static void get_auth_class(peer_cfg_t *peer_cfg, bool local, + auth_class_t *c1, auth_class_t *c2) +{ + enumerator_t *enumerator; + auth_cfg_t *auth; + + *c1 = *c2 = AUTH_CLASS_ANY; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) + { + if (*c1 == AUTH_CLASS_ANY) + { + *c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + } + else + { + *c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Select an auth method to use by checking what key we have + */ +static auth_method_t get_pubkey_method(private_phase1_t *this, auth_cfg_t *auth) +{ + auth_method_t method = AUTH_NONE; + identification_t *id; + private_key_t *private; + + if (auth) + { + id = (identification_t*)auth->get(auth, AUTH_RULE_IDENTITY); + if (id) + { + private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, NULL); + if (private) + { + switch (private->get_type(private)) + { + case KEY_RSA: + method = AUTH_RSA; + break; + case KEY_ECDSA: + switch (private->get_keysize(private)) + { + case 256: + method = AUTH_ECDSA_256; + break; + case 384: + method = AUTH_ECDSA_384; + break; + case 521: + method = AUTH_ECDSA_521; + break; + default: + DBG1(DBG_IKE, "%d bit ECDSA private key size not " + "supported", private->get_keysize(private)); + break; + } + break; + default: + DBG1(DBG_IKE, "private key of type %N not supported", + key_type_names, private->get_type(private)); + break; + } + private->destroy(private); + } + else + { + DBG1(DBG_IKE, "no private key found for '%Y'", id); + } + } + } + return method; +} + +/** + * Calculate authentication method from a peer config + */ +static auth_method_t calc_auth_method(private_phase1_t *this, + peer_cfg_t *peer_cfg) +{ + auth_class_t i1, i2, r1, r2; + + get_auth_class(peer_cfg, this->initiator, &i1, &i2); + get_auth_class(peer_cfg, !this->initiator, &r1, &r2); + + if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + /* for any pubkey method, return RSA */ + return AUTH_RSA; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_RSA; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_RSA; + } + } + if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_PSK; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_PSK; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_PSK; + } + } + if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY && + i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_HYBRID_INIT_RSA; + } + return AUTH_NONE; +} + +METHOD(phase1_t, get_auth_method, auth_method_t, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + auth_method_t method; + + method = calc_auth_method(this, peer_cfg); + if (method == AUTH_RSA) + { + return get_pubkey_method(this, get_auth_cfg(peer_cfg, TRUE)); + } + return method; +} + +/** + * Check if a peer config can be used with a given auth method + */ +static bool check_auth_method(private_phase1_t *this, peer_cfg_t *peer_cfg, + auth_method_t given) +{ + auth_method_t method; + + method = calc_auth_method(this, peer_cfg); + switch (given) + { + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + return method == AUTH_RSA; + default: + return method == given; + } +} + +METHOD(phase1_t, select_config, peer_cfg_t*, + private_phase1_t *this, auth_method_t method, bool aggressive, + identification_t *id) +{ + enumerator_t *enumerator; + peer_cfg_t *current; + host_t *me, *other; + + if (this->peer_cfg) + { /* try to find an alternative config */ + if (this->candidates->remove_first(this->candidates, + (void**)¤t) != SUCCESS) + { + DBG1(DBG_CFG, "no alternative config found"); + return NULL; + } + DBG1(DBG_CFG, "switching to peer config '%s'", + current->get_name(current)); + return current; + } + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]", + auth_method_names, method, me, other, id); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, NULL, id, IKEV1); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (check_auth_method(this, current, method) && + current->use_aggressive(current) == aggressive) + { + current->get_ref(current); + if (!this->peer_cfg) + { + this->peer_cfg = current; + } + else + { + this->candidates->insert_last(this->candidates, current); + } + } + } + enumerator->destroy(enumerator); + + if (this->peer_cfg) + { + DBG1(DBG_CFG, "selected peer config \"%s\"", + this->peer_cfg->get_name(this->peer_cfg)); + return this->peer_cfg->get_ref(this->peer_cfg); + } + DBG1(DBG_IKE, "no peer config found"); + return NULL; +} + +METHOD(phase1_t, get_id, identification_t*, + private_phase1_t *this, peer_cfg_t *peer_cfg, bool local) +{ + identification_t *id = NULL; + auth_cfg_t *auth; + + auth = get_auth_cfg(peer_cfg, local); + if (auth) + { + id = auth->get(auth, AUTH_RULE_IDENTITY); + if (local && (!id || id->get_type(id) == ID_ANY)) + { /* no ID configured, use local IP address */ + host_t *me; + + me = this->ike_sa->get_my_host(this->ike_sa); + if (!me->is_anyaddr(me)) + { + id = identification_create_from_sockaddr(me->get_sockaddr(me)); + auth->add(auth, AUTH_RULE_IDENTITY, id); + } + } + } + return id; +} + +METHOD(phase1_t, has_virtual_ip, bool, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + bool found = FALSE; + host_t *host; + + enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg); + found = enumerator->enumerate(enumerator, &host); + enumerator->destroy(enumerator); + + return found; +} + +METHOD(phase1_t, has_pool, bool, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + enumerator_t *enumerator; + bool found = FALSE; + char *pool; + + enumerator = peer_cfg->create_pool_enumerator(peer_cfg); + found = enumerator->enumerate(enumerator, &pool); + enumerator->destroy(enumerator); + + return found; +} + +METHOD(phase1_t, save_sa_payload, bool, + private_phase1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload, *sa = NULL; + chunk_t data; + size_t offset = IKE_HEADER_LENGTH; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa = payload; + break; + } + else + { + offset += payload->get_length(payload); + } + } + enumerator->destroy(enumerator); + + data = message->get_packet_data(message); + if (sa && data.len >= offset + sa->get_length(sa)) + { + /* Get SA payload without 4 byte fixed header */ + data = chunk_skip(data, offset); + data.len = sa->get_length(sa); + data = chunk_skip(data, 4); + this->sa_payload = chunk_clone(data); + return TRUE; + } + DBG1(DBG_IKE, "unable to extract SA payload encoding"); + return FALSE; +} + +METHOD(phase1_t, add_nonce_ke, bool, + private_phase1_t *this, message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + nonce_gen_t *nonceg; + chunk_t nonce; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh); + message->add_payload(message, &ke_payload->payload_interface); + + nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); + if (!nonceg) + { + DBG1(DBG_IKE, "no nonce generator found to create nonce"); + return FALSE; + } + if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &nonce)) + { + DBG1(DBG_IKE, "nonce allocation failed"); + nonceg->destroy(nonceg); + return FALSE; + } + nonceg->destroy(nonceg); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, nonce); + message->add_payload(message, &nonce_payload->payload_interface); + + if (this->initiator) + { + this->nonce_i = nonce; + } + else + { + this->nonce_r = nonce; + } + return TRUE; +} + +METHOD(phase1_t, get_nonce_ke, bool, + private_phase1_t *this, message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing in message"); + return FALSE; + } + this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload)); + this->dh->set_other_public_value(this->dh, this->dh_value); + + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "NONCE payload missing in message"); + return FALSE; + } + + if (this->initiator) + { + this->nonce_r = nonce_payload->get_nonce(nonce_payload); + } + else + { + this->nonce_i = nonce_payload->get_nonce(nonce_payload); + } + return TRUE; +} + +METHOD(phase1_t, destroy, void, + private_phase1_t *this) +{ + DESTROY_IF(this->peer_cfg); + this->candidates->destroy_offset(this->candidates, + offsetof(peer_cfg_t, destroy)); + chunk_free(&this->sa_payload); + DESTROY_IF(this->dh); + free(this->dh_value.ptr); + free(this->nonce_i.ptr); + free(this->nonce_r.ptr); + free(this); +} + +/** + * See header + */ +phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_phase1_t *this; + + INIT(this, + .public = { + .create_hasher = _create_hasher, + .create_dh = _create_dh, + .derive_keys = _derive_keys, + .get_auth_method = _get_auth_method, + .get_id = _get_id, + .select_config = _select_config, + .has_virtual_ip = _has_virtual_ip, + .has_pool = _has_pool, + .verify_auth = _verify_auth, + .build_auth = _build_auth, + .save_sa_payload = _save_sa_payload, + .add_nonce_ke = _add_nonce_ke, + .get_nonce_ke = _get_nonce_ke, + .destroy = _destroy, + }, + .candidates = linked_list_create(), + .ike_sa = ike_sa, + .initiator = initiator, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h new file mode 100644 index 000000000..eaf8908e7 --- /dev/null +++ b/src/libcharon/sa/ikev1/phase1.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup phase1 phase1 + * @{ @ingroup ikev1 + */ + +#ifndef PHASE1_H_ +#define PHASE1_H_ + +typedef struct phase1_t phase1_t; + +#include +#include + +/** + * Common phase 1 helper for main and aggressive mode. + */ +struct phase1_t { + + /** + * Create keymat hasher. + * + * @return TRUE if hasher created + */ + bool (*create_hasher)(phase1_t *this); + + /** + * Create DH object using SA keymat. + * + * @param group negotiated DH group + * @return TRUE if group supported + */ + bool (*create_dh)(phase1_t *this, diffie_hellman_group_t group); + + /** + * Derive key material. + * + * @param peer_cfg peer config to look up shared key for, or NULL + * @param method negotiated authenticated method + * @return TRUE if successful + */ + bool (*derive_keys)(phase1_t *this, peer_cfg_t *peer_cfg, + auth_method_t method); + /** + * Verify a HASH or SIG payload in message. + * + * @param method negotiated auth method + * @param message message containing HASH or SIG payload + * @param id_data encoded identity, including protocol/port fields + * @return TRUE if verified successfully + */ + bool (*verify_auth)(phase1_t *this, auth_method_t method, + message_t *message, chunk_t id_data); + + /** + * Build a HASH or SIG payload and add it to message. + * + * @param method negotiated auth method + * @param message message to add payload to + * @param id_data encoded identity, including protocol/port fields + * @return TRUE if built successfully + */ + bool (*build_auth)(phase1_t *this, auth_method_t method, + message_t *message, chunk_t id_data); + + /** + * Get the IKEv1 authentication method defined by peer config. + * + * @param peer_cfg peer config to get auth method from + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(phase1_t *this, peer_cfg_t *peer_cfg); + + /** + * Select a peer config as responder. + * + * If called after the first successful call the next alternative config + * is returned, if any. + * + * @param method used authentication method + * @param aggressive TRUE to get an aggressive mode config + * @param id initiator identity + * @return selected peer config, NULL if none found + */ + peer_cfg_t* (*select_config)(phase1_t *this, auth_method_t method, + bool aggressive, identification_t *id); + + /** + * Get configured identity from peer config. + * + * @param peer_cfg peer config to get identity from + * @param local TRUE to get own identity, FALSE for remote + * @return identity, pointing to internal config data + */ + identification_t* (*get_id)(phase1_t *this, peer_cfg_t *peer_cfg, bool local); + + /** + * Check if peer config has virtual IPs pool assigned. + * + * @param peer_cfg peer_config to check + * @return TRUE if peer config contains at least one pool + */ + bool (*has_pool)(phase1_t *this, peer_cfg_t *peer_cfg); + + /** + * Check if peer config has virtual IPs to request + * + * @param peer_cfg peer_config to check + * @return TRUE if peer config contains at least one virtual IP + */ + bool (*has_virtual_ip)(phase1_t *this, peer_cfg_t *peer_cfg); + + /** + * Extract and store SA payload bytes from encoded message. + * + * @param message message to extract SA payload bytes from + * @return TRUE if SA payload found + */ + bool (*save_sa_payload)(phase1_t *this, message_t *message); + + /** + * Add Nonce and KE payload to message. + * + * @param message message to add payloads + * @return TRUE if payloads added successfully + */ + bool (*add_nonce_ke)(phase1_t *this, message_t *message); + + /** + * Extract Nonce and KE payload from message. + * + * @param message message to get payloads from + * @return TRUE if payloads extracted successfully + */ + bool (*get_nonce_ke)(phase1_t *this, message_t *message); + + /** + * Destroy a phase1_t. + */ + void (*destroy)(phase1_t *this); +}; + +/** + * Create a phase1 instance. + * + * @param ike_sa IKE_SA to set up + * @param initiator TRUE if initiating actively + * @return Phase 1 helper + */ +phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** PHASE1_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c new file mode 100644 index 000000000..fd0ad235a --- /dev/null +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -0,0 +1,1714 @@ +/* + * Copyright (C) 2007-2011 Tobias Brunner + * Copyright (C) 2007-2011 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "task_manager_v1.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/** + * Number of old messages hashes we keep for retransmission. + * + * In Main Mode, we must ignore messages from a previous message pair if + * we already continued to the next. Otherwise a late retransmission + * could be considered as a reply to the newer request. + */ +#define MAX_OLD_HASHES 2 + +/** + * First sequence number of responding packets. + * + * To distinguish retransmission jobs for initiating and responding packets, + * we split up the sequence counter and use the upper half for responding. + */ +#define RESPONDING_SEQ INT_MAX + +typedef struct exchange_t exchange_t; + +/** + * An exchange in the air, used do detect and handle retransmission + */ +struct exchange_t { + + /** + * Message ID used for this transaction + */ + u_int32_t mid; + + /** + * generated packet for retransmission + */ + packet_t *packet; +}; + +typedef struct private_task_manager_t private_task_manager_t; + +/** + * private data of the task manager + */ +struct private_task_manager_t { + + /** + * public functions + */ + task_manager_v1_t public; + + /** + * associated IKE_SA we are serving + */ + ike_sa_t *ike_sa; + + /** + * RNG to create message IDs + */ + rng_t *rng; + + /** + * Exchange we are currently handling as responder + */ + struct { + /** + * Message ID of the last response + */ + u_int32_t mid; + + /** + * Hash of a previously received message + */ + u_int32_t hash; + + /** + * packet for retransmission + */ + packet_t *packet; + + /** + * Sequence number of the last sent message + */ + u_int32_t seqnr; + + /** + * how many times we have retransmitted so far + */ + u_int retransmitted; + + } responding; + + /** + * Exchange we are currently handling as initiator + */ + struct { + /** + * Message ID of the exchange + */ + u_int32_t mid; + + /** + * Hashes of old responses we can ignore + */ + u_int32_t old_hashes[MAX_OLD_HASHES]; + + /** + * Position in old hash array + */ + int old_hash_pos; + + /** + * Sequence number of the last sent message + */ + u_int32_t seqnr; + + /** + * how many times we have retransmitted so far + */ + u_int retransmitted; + + /** + * packet for retransmission + */ + packet_t *packet; + + /** + * type of the initated exchange + */ + exchange_type_t type; + + } initiating; + + /** + * List of queued tasks not yet in action + */ + linked_list_t *queued_tasks; + + /** + * List of active tasks, initiated by ourselve + */ + linked_list_t *active_tasks; + + /** + * List of tasks initiated by peer + */ + linked_list_t *passive_tasks; + + /** + * Queued messages not yet ready to process + */ + message_t *queued; + + /** + * Number of times we retransmit messages before giving up + */ + u_int retransmit_tries; + + /** + * Retransmission timeout + */ + double retransmit_timeout; + + /** + * Base to calculate retransmission timeout + */ + double retransmit_base; + + /** + * Sequence number for sending DPD requests + */ + u_int32_t dpd_send; + + /** + * Sequence number for received DPD requests + */ + u_int32_t dpd_recv; +}; + +METHOD(task_manager_t, flush_queue, void, + private_task_manager_t *this, task_queue_t queue) +{ + linked_list_t *list; + task_t *task; + + if (this->queued) + { + this->queued->destroy(this->queued); + this->queued = NULL; + } + switch (queue) + { + case TASK_QUEUE_ACTIVE: + list = this->active_tasks; + /* cancel pending retransmits */ + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + DESTROY_IF(this->initiating.packet); + this->initiating.packet = NULL; + break; + case TASK_QUEUE_PASSIVE: + list = this->passive_tasks; + break; + case TASK_QUEUE_QUEUED: + list = this->queued_tasks; + break; + default: + return; + } + while (list->remove_last(list, (void**)&task) == SUCCESS) + { + task->destroy(task); + } +} + +/** + * flush all tasks in the task manager + */ +static void flush(private_task_manager_t *this) +{ + flush_queue(this, TASK_QUEUE_QUEUED); + flush_queue(this, TASK_QUEUE_PASSIVE); + flush_queue(this, TASK_QUEUE_ACTIVE); +} + +/** + * move a task of a specific type from the queue to the active list + */ +static bool activate_task(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + task_t *task; + bool found = FALSE; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + if (task->get_type(task) == type) + { + DBG2(DBG_IKE, " activating %N task", task_type_names, type); + this->queued_tasks->remove_at(this->queued_tasks, enumerator); + this->active_tasks->insert_last(this->active_tasks, task); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Retransmit a packet, either as initiator or as responder + */ +static status_t retransmit_packet(private_task_manager_t *this, u_int32_t seqnr, + u_int mid, u_int retransmitted, packet_t *packet) +{ + u_int32_t t; + + if (retransmitted > this->retransmit_tries) + { + DBG1(DBG_IKE, "giving up after %u retransmits", retransmitted - 1); + return DESTROY_ME; + } + t = (u_int32_t)(this->retransmit_timeout * 1000.0 * + pow(this->retransmit_base, retransmitted)); + if (retransmitted) + { + DBG1(DBG_IKE, "sending retransmit %u of %s message ID %u, seq %u", + retransmitted, seqnr < RESPONDING_SEQ ? "request" : "response", + mid, seqnr < RESPONDING_SEQ ? seqnr : seqnr - RESPONDING_SEQ); + } + charon->sender->send(charon->sender, packet->clone(packet)); + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) + retransmit_job_create(seqnr, this->ike_sa->get_id(this->ike_sa)), t); + return NEED_MORE; +} + +METHOD(task_manager_t, retransmit, status_t, + private_task_manager_t *this, u_int32_t seqnr) +{ + status_t status = SUCCESS; + + if (seqnr == this->initiating.seqnr && this->initiating.packet) + { + status = retransmit_packet(this, seqnr, this->initiating.mid, + this->initiating.retransmitted, this->initiating.packet); + if (status == NEED_MORE) + { + this->initiating.retransmitted++; + status = SUCCESS; + } + } + if (seqnr == this->responding.seqnr && this->responding.packet) + { + status = retransmit_packet(this, seqnr, this->responding.mid, + this->responding.retransmitted, this->responding.packet); + if (status == NEED_MORE) + { + this->responding.retransmitted++; + status = SUCCESS; + } + } + return status; +} + +/** + * Check if we have to wait for a mode config before starting a quick mode + */ +static bool mode_config_expected(private_task_manager_t *this) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + char *pool; + host_t *host; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_pool_enumerator(peer_cfg); + if (!enumerator->enumerate(enumerator, &pool)) + { /* no pool configured */ + enumerator->destroy(enumerator); + return FALSE; + } + enumerator->destroy(enumerator); + + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, + FALSE); + if (!enumerator->enumerate(enumerator, &host)) + { /* have a pool, but no VIP assigned yet */ + enumerator->destroy(enumerator); + return TRUE; + } + enumerator->destroy(enumerator); + } + return FALSE; +} + +METHOD(task_manager_t, initiate, status_t, + private_task_manager_t *this) +{ + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + status_t status; + exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; + bool new_mid = FALSE, expect_response = FALSE, cancelled = FALSE, keep = FALSE; + + if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED && + this->initiating.type != INFORMATIONAL_V1) + { + DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", + exchange_type_names, this->initiating.type); + /* do not initiate if we already have a message in the air */ + return SUCCESS; + } + + if (this->active_tasks->get_count(this->active_tasks) == 0) + { + DBG2(DBG_IKE, "activating new tasks"); + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_CREATED: + activate_task(this, TASK_ISAKMP_VENDOR); + activate_task(this, TASK_ISAKMP_CERT_PRE); + if (activate_task(this, TASK_MAIN_MODE)) + { + exchange = ID_PROT; + } + else if (activate_task(this, TASK_AGGRESSIVE_MODE)) + { + exchange = AGGRESSIVE; + } + activate_task(this, TASK_ISAKMP_CERT_POST); + activate_task(this, TASK_ISAKMP_NATD); + break; + case IKE_CONNECTING: + if (activate_task(this, TASK_ISAKMP_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_XAUTH)) + { + exchange = TRANSACTION; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_INFORMATIONAL)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + break; + case IKE_ESTABLISHED: + if (activate_task(this, TASK_MODE_CONFIG)) + { + exchange = TRANSACTION; + new_mid = TRUE; + break; + } + if (!mode_config_expected(this) && + activate_task(this, TASK_QUICK_MODE)) + { + exchange = QUICK_MODE; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_INFORMATIONAL)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_QUICK_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_ISAKMP_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + if (activate_task(this, TASK_ISAKMP_DPD)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + break; + default: + break; + } + } + else + { + DBG2(DBG_IKE, "reinitiating already active tasks"); + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); + switch (task->get_type(task)) + { + case TASK_MAIN_MODE: + exchange = ID_PROT; + break; + case TASK_AGGRESSIVE_MODE: + exchange = AGGRESSIVE; + break; + case TASK_QUICK_MODE: + exchange = QUICK_MODE; + break; + case TASK_XAUTH: + exchange = TRANSACTION; + new_mid = TRUE; + break; + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + } + + if (exchange == EXCHANGE_TYPE_UNDEFINED) + { + DBG2(DBG_IKE, "nothing to initiate"); + /* nothing to do yet... */ + return SUCCESS; + } + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + + if (new_mid) + { + if (!this->rng->get_bytes(this->rng, sizeof(this->initiating.mid), + (void*)&this->initiating.mid)) + { + DBG1(DBG_IKE, "failed to allocate message ID, destroying IKE_SA"); + flush(this); + return DESTROY_ME; + } + } + message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + message->set_message_id(message, this->initiating.mid); + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_exchange_type(message, exchange); + this->initiating.type = exchange; + this->initiating.retransmitted = 0; + + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + if (task->get_type(task) == TASK_AGGRESSIVE_MODE || + task->get_type(task) == TASK_QUICK_MODE) + { /* last message of three message exchange */ + keep = TRUE; + } + task->destroy(task); + continue; + case NEED_MORE: + expect_response = TRUE; + /* processed, but task needs another exchange */ + continue; + case ALREADY_DONE: + cancelled = TRUE; + break; + case FAILED: + default: + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + enumerator->destroy(enumerator); + message->destroy(message); + flush(this); + return DESTROY_ME; + } + break; + } + enumerator->destroy(enumerator); + + if (this->active_tasks->get_count(this->active_tasks) == 0 && + (exchange == QUICK_MODE || exchange == AGGRESSIVE)) + { /* tasks completed, no exchange active anymore */ + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + } + if (cancelled) + { + message->destroy(message); + return initiate(this); + } + + DESTROY_IF(this->initiating.packet); + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->initiating.packet); + if (status != SUCCESS) + { + /* message generation failed. There is nothing more to do than to + * close the SA */ + message->destroy(message); + flush(this); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + this->initiating.seqnr++; + if (expect_response) + { + message->destroy(message); + return retransmit(this, this->initiating.seqnr); + } + if (keep) + { /* keep the packet for retransmission, the responder might request it */ + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + } + else + { + charon->sender->send(charon->sender, this->initiating.packet); + this->initiating.packet = NULL; + } + message->destroy(message); + + if (exchange == INFORMATIONAL_V1) + { + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_CONNECTING: + /* close after sending an INFORMATIONAL when unestablished */ + return FAILED; + case IKE_DELETING: + /* close after sending a DELETE */ + return DESTROY_ME; + default: + break; + } + } + return initiate(this); +} + +/** + * build a response depending on the "passive" task list + */ +static status_t build_response(private_task_manager_t *this, message_t *request) +{ + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + bool delete = FALSE, cancelled = FALSE, expect_request = FALSE; + status_t status; + + me = request->get_destination(request); + other = request->get_source(request); + + message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + message->set_exchange_type(message, request->get_exchange_type(request)); + /* send response along the path the request came in */ + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_message_id(message, request->get_message_id(request)); + message->set_request(message, FALSE); + + this->responding.mid = request->get_message_id(request); + this->responding.retransmitted = 0; + this->responding.seqnr++; + + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + task->destroy(task); + continue; + case NEED_MORE: + /* processed, but task needs another exchange */ + if (task->get_type(task) == TASK_QUICK_MODE || + task->get_type(task) == TASK_AGGRESSIVE_MODE) + { /* we rely on initiator retransmission, except for + * three-message exchanges */ + expect_request = TRUE; + } + continue; + case ALREADY_DONE: + cancelled = TRUE; + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* destroy IKE_SA, but SEND response first */ + delete = TRUE; + break; + } + break; + } + enumerator->destroy(enumerator); + + DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; + if (cancelled) + { + message->destroy(message); + return initiate(this); + } + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->responding.packet); + message->destroy(message); + if (status != SUCCESS) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + if (expect_request && !delete) + { + return retransmit(this, this->responding.seqnr); + } + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + if (delete) + { + return DESTROY_ME; + } + return SUCCESS; +} + +/** + * Send a notify in a separate INFORMATIONAL exchange back to the sender. + * The notify protocol_id is set to ISAKMP + */ +static void send_notify(private_task_manager_t *this, message_t *request, + notify_type_t type) +{ + message_t *response; + packet_t *packet; + host_t *me, *other; + u_int32_t mid; + + if (request->get_exchange_type(request) == INFORMATIONAL_V1) + { /* don't respond to INFORMATIONAL requests to avoid a notify war */ + DBG1(DBG_IKE, "ignore malformed INFORMATIONAL request"); + return; + } + if (!this->rng->get_bytes(this->rng, sizeof(mid), (void*)&mid)) + { + DBG1(DBG_IKE, "failed to allocate message ID"); + return; + } + response = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + response->set_exchange_type(response, INFORMATIONAL_V1); + response->set_request(response, TRUE); + response->set_message_id(response, mid); + response->add_payload(response, (payload_t*) + notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type)); + + me = this->ike_sa->get_my_host(this->ike_sa); + if (me->is_anyaddr(me)) + { + me = request->get_destination(request); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + } + other = this->ike_sa->get_other_host(this->ike_sa); + if (other->is_anyaddr(other)) + { + other = request->get_source(request); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + response->set_source(response, me->clone(me)); + response->set_destination(response, other->clone(other)); + if (this->ike_sa->generate_message(this->ike_sa, response, + &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); +} + +/** + * Process a DPD request/response + */ +static bool process_dpd(private_task_manager_t *this, message_t *message) +{ + notify_payload_t *notify; + notify_type_t type; + u_int32_t seq; + chunk_t data; + + type = DPD_R_U_THERE; + notify = message->get_notify(message, type); + if (!notify) + { + type = DPD_R_U_THERE_ACK; + notify = message->get_notify(message, type); + } + if (!notify) + { + return FALSE; + } + data = notify->get_notification_data(notify); + if (data.len != 4) + { + return FALSE; + } + seq = untoh32(data.ptr); + + if (type == DPD_R_U_THERE) + { + if (this->dpd_recv == 0 || seq == this->dpd_recv) + { /* check sequence validity */ + this->dpd_recv = seq + 1; + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } + /* but respond anyway */ + this->ike_sa->queue_task(this->ike_sa, + &isakmp_dpd_create(this->ike_sa, DPD_R_U_THERE_ACK, seq)->task); + } + else /* DPD_R_U_THERE_ACK */ + { + if (seq == this->dpd_send - 1) + { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } + else + { + DBG1(DBG_IKE, "received invalid DPD sequence number %u " + "(expected %u), ignored", seq, this->dpd_send - 1); + } + } + return TRUE; +} + +/** + * handle an incoming request message + */ +static status_t process_request(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + task_t *task = NULL; + bool send_response = FALSE, dpd = FALSE; + + if (message->get_exchange_type(message) == INFORMATIONAL_V1 || + this->passive_tasks->get_count(this->passive_tasks) == 0) + { /* create tasks depending on request type, if not already some queued */ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + task = (task_t *)isakmp_vendor_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)main_mode_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + case AGGRESSIVE: + task = (task_t *)isakmp_vendor_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)aggressive_mode_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + case QUICK_MODE: + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + DBG1(DBG_IKE, "received quick mode request for " + "unestablished IKE_SA, ignored"); + return FAILED; + } + task = (task_t *)quick_mode_create(this->ike_sa, NULL, + NULL, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + case INFORMATIONAL_V1: + if (process_dpd(this, message)) + { + dpd = TRUE; + } + else + { + task = (task_t *)informational_create(this->ike_sa, NULL); + this->passive_tasks->insert_first(this->passive_tasks, task); + } + break; + case TRANSACTION: + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + task = (task_t *)mode_config_create(this->ike_sa, FALSE); + } + else + { + task = (task_t *)xauth_create(this->ike_sa, FALSE); + } + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + default: + return FAILED; + } + } + if (dpd) + { + return initiate(this); + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, time_monotonic(NULL)); + + /* let the tasks process the message */ + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + task->destroy(task); + continue; + case NEED_MORE: + /* processed, but task needs at least another call to build() */ + send_response = TRUE; + continue; + case ALREADY_DONE: + send_response = FALSE; + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + break; + } + enumerator->destroy(enumerator); + + if (send_response) + { + if (build_response(this, message) != SUCCESS) + { + return DESTROY_ME; + } + } + else + { /* We don't send a response, so don't retransmit one if we get + * the same message again. */ + DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; + } + if (this->passive_tasks->get_count(this->passive_tasks) == 0 && + this->queued_tasks->get_count(this->queued_tasks) > 0) + { + /* passive tasks completed, check if an active task has been queued, + * such as XAUTH or modeconfig push */ + return initiate(this); + } + return SUCCESS; +} + +/** + * handle an incoming response message + */ +static status_t process_response(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + message_t *queued; + status_t status; + task_t *task; + + if (message->get_exchange_type(message) != this->initiating.type) + { + DBG1(DBG_IKE, "received %N response, but expected %N", + exchange_type_names, message->get_exchange_type(message), + exchange_type_names, this->initiating.type); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + continue; + case NEED_MORE: + /* processed, but task needs another exchange */ + continue; + case ALREADY_DONE: + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + break; + } + enumerator->destroy(enumerator); + + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + DESTROY_IF(this->initiating.packet); + this->initiating.packet = NULL; + + if (this->queued && this->active_tasks->get_count(this->active_tasks) == 0) + { + queued = this->queued; + this->queued = NULL; + status = this->public.task_manager.process_message( + &this->public.task_manager, queued); + queued->destroy(queued); + if (status == DESTROY_ME) + { + return status; + } + } + + return initiate(this); +} + +/** + * Parse the given message and verify that it is valid. + */ +static status_t parse_message(private_task_manager_t *this, message_t *msg) +{ + status_t status; + + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + + if (status != SUCCESS) + { + switch (status) + { + case NOT_SUPPORTED: + DBG1(DBG_IKE, "unsupported exchange type"); + send_notify(this, msg, INVALID_EXCHANGE_TYPE); + break; + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + send_notify(this, msg, PAYLOAD_MALFORMED); + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + send_notify(this, msg, PAYLOAD_MALFORMED); + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + send_notify(this, msg, INVALID_HASH_INFORMATION); + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + send_notify(this, msg, PAYLOAD_MALFORMED); + default: + break; + } + DBG1(DBG_IKE, "%N %s with message ID %u processing failed", + exchange_type_names, msg->get_exchange_type(msg), + msg->get_request(msg) ? "request" : "response", + msg->get_message_id(msg)); + + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED) + { /* invalid initiation attempt, close SA */ + return DESTROY_ME; + } + } + return status; +} + +METHOD(task_manager_t, process_message, status_t, + private_task_manager_t *this, message_t *msg) +{ + u_int32_t hash, mid, i; + host_t *me, *other; + status_t status; + + /* TODO-IKEv1: update hosts more selectively */ + me = msg->get_destination(msg); + other = msg->get_source(msg); + mid = msg->get_message_id(msg); + hash = chunk_hash(msg->get_packet_data(msg)); + for (i = 0; i < MAX_OLD_HASHES; i++) + { + if (this->initiating.old_hashes[i] == hash) + { + if (this->initiating.packet && + i == (this->initiating.old_hash_pos % MAX_OLD_HASHES) && + (msg->get_exchange_type(msg) == QUICK_MODE || + msg->get_exchange_type(msg) == AGGRESSIVE)) + { + DBG1(DBG_IKE, "received retransmit of response with ID %u, " + "resending last request", mid); + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + return SUCCESS; + } + DBG1(DBG_IKE, "received retransmit of response with ID %u, " + "but next request already sent", mid); + return SUCCESS; + } + } + + if ((mid && mid == this->initiating.mid) || + (this->initiating.mid == 0 && + msg->get_exchange_type(msg) == this->initiating.type && + this->active_tasks->get_count(this->active_tasks))) + { + msg->set_request(msg, FALSE); + charon->bus->message(charon->bus, msg, TRUE, FALSE); + status = parse_message(this, msg); + if (status != SUCCESS) + { + return status; + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); + if (process_response(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + this->initiating.old_hashes[(++this->initiating.old_hash_pos) % + MAX_OLD_HASHES] = hash; + } + else + { + if (hash == this->responding.hash) + { + if (this->responding.packet) + { + DBG1(DBG_IKE, "received retransmit of request with ID %u, " + "retransmitting response", mid); + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + } + else if (this->initiating.packet && + this->initiating.type == INFORMATIONAL_V1) + { + DBG1(DBG_IKE, "received retransmit of DPD request, " + "retransmitting response"); + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + } + else + { + DBG1(DBG_IKE, "received retransmit of request with ID %u, " + "but no response to retransmit", mid); + } + return SUCCESS; + } + if (msg->get_exchange_type(msg) == TRANSACTION && + this->active_tasks->get_count(this->active_tasks)) + { /* main mode not yet complete, queue XAuth/Mode config tasks */ + if (this->queued) + { + DBG1(DBG_IKE, "ignoring additional %N request, queue full", + exchange_type_names, TRANSACTION); + return SUCCESS; + } + this->queued = message_create_from_packet(msg->get_packet(msg)); + if (this->queued->parse_header(this->queued) != SUCCESS) + { + this->queued->destroy(this->queued); + this->queued = NULL; + return FAILED; + } + DBG1(DBG_IKE, "queueing %N request as tasks still active", + exchange_type_names, TRANSACTION); + return SUCCESS; + } + + msg->set_request(msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, FALSE); + status = parse_message(this, msg); + if (status != SUCCESS) + { + return status; + } + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) + { + ike_sa_id_t *ike_sa_id; + ike_cfg_t *ike_cfg; + job_t *job; + + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); + if (ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", + me, other, notify_type_names, NO_PROPOSAL_CHOSEN); + send_notify(this, msg, NO_PROPOSAL_CHOSEN); + return DESTROY_ME; + } + this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); + ike_cfg->destroy(ike_cfg); + /* add a timeout if peer does not establish it completely */ + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, + lib->settings->get_int(lib->settings, + "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT, + charon->name)); + } + this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); + if (process_request(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + this->responding.hash = hash; + } + return SUCCESS; +} + +METHOD(task_manager_t, queue_task, void, + private_task_manager_t *this, task_t *task) +{ + DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); + this->queued_tasks->insert_last(this->queued_tasks, task); +} + +/** + * Check if a given task has been queued already + */ +static bool has_queued(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + bool found = FALSE; + task_t *task; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == type) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +METHOD(task_manager_t, queue_ike, void, + private_task_manager_t *this) +{ + peer_cfg_t *peer_cfg; + + if (!has_queued(this, TASK_ISAKMP_VENDOR)) + { + queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_ISAKMP_CERT_PRE)) + { + queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE)); + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->use_aggressive(peer_cfg)) + { + if (!has_queued(this, TASK_AGGRESSIVE_MODE)) + { + queue_task(this, (task_t*)aggressive_mode_create(this->ike_sa, TRUE)); + } + } + else + { + if (!has_queued(this, TASK_MAIN_MODE)) + { + queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); + } + } + if (!has_queued(this, TASK_ISAKMP_CERT_POST)) + { + queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_ISAKMP_NATD)) + { + queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); + } +} + +METHOD(task_manager_t, queue_ike_reauth, void, + private_task_manager_t *this) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + ike_sa_t *new; + host_t *host; + + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->ike_sa->get_version(this->ike_sa), TRUE); + if (!new) + { /* shouldn't happen */ + return; + } + + new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa)); + host = this->ike_sa->get_other_host(this->ike_sa); + new->set_other_host(new, host->clone(host)); + host = this->ike_sa->get_my_host(this->ike_sa); + new->set_my_host(new, host->clone(host)); + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + new->add_virtual_ip(new, TRUE, host); + } + enumerator->destroy(enumerator); + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + this->ike_sa->remove_child_sa(this->ike_sa, enumerator); + new->add_child_sa(new, child_sa); + } + enumerator->destroy(enumerator); + + if (!new->get_child_count(new)) + { /* check if a Quick Mode task is queued (UNITY_LOAD_BALANCE case) */ + task_t *task; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == TASK_QUICK_MODE) + { + this->queued_tasks->remove_at(this->queued_tasks, enumerator); + task->migrate(task, new); + new->queue_task(new, task); + } + } + enumerator->destroy(enumerator); + } + + if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME) + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); + } + else + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new); + DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); + } + charon->bus->set_sa(charon->bus, this->ike_sa); +} + +METHOD(task_manager_t, queue_ike_rekey, void, + private_task_manager_t *this) +{ + queue_ike_reauth(this); +} + +METHOD(task_manager_t, queue_ike_delete, void, + private_task_manager_t *this) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + queue_task(this, (task_t*) + quick_delete_create(this->ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE), FALSE, FALSE)); + } + enumerator->destroy(enumerator); + + queue_task(this, (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); +} + +METHOD(task_manager_t, queue_mobike, void, + private_task_manager_t *this, bool roam, bool address) +{ + /* Not supported in IKEv1 */ +} + +METHOD(task_manager_t, queue_child, void, + private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + quick_mode_t *task; + + task = quick_mode_create(this->ike_sa, cfg, tsi, tsr); + task->use_reqid(task, reqid); + + queue_task(this, &task->task); +} + +/** + * Check if two CHILD_SAs have the same traffic selector + */ +static bool have_equal_ts(child_sa_t *a, child_sa_t *b, bool local) +{ + linked_list_t *list; + traffic_selector_t *ts_a, *ts_b; + + list = a->get_traffic_selectors(a, local); + if (list->get_first(list, (void**)&ts_a) == SUCCESS) + { + list = b->get_traffic_selectors(b, local); + if (list->get_first(list, (void**)&ts_b) == SUCCESS) + { + return ts_a->equals(ts_a, ts_b); + } + } + return FALSE; +} + +/** + * Check if a CHILD_SA is redundant and we should delete instead of rekey + */ +static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa) +{ + enumerator_t *enumerator; + child_sa_t *current; + bool redundant = FALSE; + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->get_state(current) == CHILD_INSTALLED && + streq(current->get_name(current), child_sa->get_name(child_sa)) && + have_equal_ts(current, child_sa, TRUE) && + have_equal_ts(current, child_sa, FALSE) && + current->get_lifetime(current, FALSE) > + child_sa->get_lifetime(child_sa, FALSE)) + { + DBG1(DBG_IKE, "deleting redundant CHILD_SA %s{%d}", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa)); + redundant = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + return redundant; +} + +/** + * Get the first traffic selector of a CHILD_SA, local or remote + */ +static traffic_selector_t* get_first_ts(child_sa_t *child_sa, bool local) +{ + traffic_selector_t *ts = NULL; + linked_list_t *list; + + list = child_sa->get_traffic_selectors(child_sa, local); + if (list->get_first(list, (void**)&ts) == SUCCESS) + { + return ts; + } + return NULL; +} + +METHOD(task_manager_t, queue_child_rekey, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + child_sa_t *child_sa; + child_cfg_t *cfg; + quick_mode_t *task; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); + if (!child_sa) + { + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE); + } + if (child_sa && child_sa->get_state(child_sa) == CHILD_INSTALLED) + { + if (is_redundant(this, child_sa)) + { + queue_task(this, (task_t*)quick_delete_create(this->ike_sa, + protocol, spi, FALSE, FALSE)); + } + else + { + child_sa->set_state(child_sa, CHILD_REKEYING); + cfg = child_sa->get_config(child_sa); + task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg), + get_first_ts(child_sa, TRUE), get_first_ts(child_sa, FALSE)); + task->use_reqid(task, child_sa->get_reqid(child_sa)); + task->rekey(task, child_sa->get_spi(child_sa, TRUE)); + + queue_task(this, &task->task); + } + } +} + +METHOD(task_manager_t, queue_child_delete, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi, + bool expired) +{ + queue_task(this, (task_t*)quick_delete_create(this->ike_sa, protocol, + spi, FALSE, expired)); +} + +METHOD(task_manager_t, queue_dpd, void, + private_task_manager_t *this) +{ + peer_cfg_t *peer_cfg; + u_int32_t t, retransmit; + + queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, DPD_R_U_THERE, + this->dpd_send++)); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + + /* compute timeout in milliseconds */ + t = 1000 * peer_cfg->get_dpd_timeout(peer_cfg); + if (t == 0) + { + /* use the same timeout as a retransmitting IKE message would have */ + for (retransmit = 0; retransmit <= this->retransmit_tries; retransmit++) + { + t += (u_int32_t)(this->retransmit_timeout * 1000.0 * + pow(this->retransmit_base, retransmit)); + } + } + + /* schedule DPD timeout job */ + lib->scheduler->schedule_job_ms(lib->scheduler, + (job_t*)dpd_timeout_job_create(this->ike_sa->get_id(this->ike_sa)), t); +} + +METHOD(task_manager_t, adopt_tasks, void, + private_task_manager_t *this, task_manager_t *other_public) +{ + private_task_manager_t *other = (private_task_manager_t*)other_public; + task_t *task; + + /* move queued tasks from other to this */ + while (other->queued_tasks->remove_last(other->queued_tasks, + (void**)&task) == SUCCESS) + { + DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } +} + +METHOD(task_manager_t, busy, bool, + private_task_manager_t *this) +{ + return (this->active_tasks->get_count(this->active_tasks) > 0); +} + +METHOD(task_manager_t, incr_mid, void, + private_task_manager_t *this, bool initiate) +{ +} + +METHOD(task_manager_t, reset, void, + private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) +{ + enumerator_t *enumerator; + task_t *task; + + /* reset message counters and retransmit packets */ + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + this->responding.packet = NULL; + this->responding.seqnr = RESPONDING_SEQ; + this->responding.retransmitted = 0; + this->initiating.packet = NULL; + this->initiating.mid = 0; + this->initiating.seqnr = 0; + this->initiating.retransmitted = 0; + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + if (initiate != UINT_MAX) + { + this->dpd_send = initiate; + } + if (respond != UINT_MAX) + { + this->dpd_recv = respond; + } + + /* reset queued tasks */ + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + task->migrate(task, this->ike_sa); + } + enumerator->destroy(enumerator); + + /* reset active tasks */ + while (this->active_tasks->remove_last(this->active_tasks, + (void**)&task) == SUCCESS) + { + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } +} + +METHOD(task_manager_t, create_task_enumerator, enumerator_t*, + private_task_manager_t *this, task_queue_t queue) +{ + switch (queue) + { + case TASK_QUEUE_ACTIVE: + return this->active_tasks->create_enumerator(this->active_tasks); + case TASK_QUEUE_PASSIVE: + return this->passive_tasks->create_enumerator(this->passive_tasks); + case TASK_QUEUE_QUEUED: + return this->queued_tasks->create_enumerator(this->queued_tasks); + default: + return enumerator_create_empty(); + } +} + +METHOD(task_manager_t, destroy, void, + private_task_manager_t *this) +{ + flush(this); + + this->active_tasks->destroy(this->active_tasks); + this->queued_tasks->destroy(this->queued_tasks); + this->passive_tasks->destroy(this->passive_tasks); + + DESTROY_IF(this->queued); + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + DESTROY_IF(this->rng); + free(this); +} + +/* + * see header file + */ +task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) +{ + private_task_manager_t *this; + + INIT(this, + .public = { + .task_manager = { + .process_message = _process_message, + .queue_task = _queue_task, + .queue_ike = _queue_ike, + .queue_ike_rekey = _queue_ike_rekey, + .queue_ike_reauth = _queue_ike_reauth, + .queue_ike_delete = _queue_ike_delete, + .queue_mobike = _queue_mobike, + .queue_child = _queue_child, + .queue_child_rekey = _queue_child_rekey, + .queue_child_delete = _queue_child_delete, + .queue_dpd = _queue_dpd, + .initiate = _initiate, + .retransmit = _retransmit, + .incr_mid = _incr_mid, + .reset = _reset, + .adopt_tasks = _adopt_tasks, + .busy = _busy, + .create_task_enumerator = _create_task_enumerator, + .flush_queue = _flush_queue, + .destroy = _destroy, + }, + }, + .initiating = { + .type = EXCHANGE_TYPE_UNDEFINED, + }, + .responding = { + .seqnr = RESPONDING_SEQ, + }, + .ike_sa = ike_sa, + .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), + .queued_tasks = linked_list_create(), + .active_tasks = linked_list_create(), + .passive_tasks = linked_list_create(), + .retransmit_tries = lib->settings->get_int(lib->settings, + "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name), + .retransmit_timeout = lib->settings->get_double(lib->settings, + "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, charon->name), + .retransmit_base = lib->settings->get_double(lib->settings, + "%s.retransmit_base", RETRANSMIT_BASE, charon->name), + ); + + if (!this->rng) + { + DBG1(DBG_IKE, "no RNG found, unable to create IKE_SA"); + destroy(this); + return NULL; + } + if (!this->rng->get_bytes(this->rng, sizeof(this->dpd_send), + (void*)&this->dpd_send)) + { + DBG1(DBG_IKE, "failed to allocate message ID, unable to create IKE_SA"); + destroy(this); + return NULL; + } + this->dpd_send &= 0x7FFFFFFF; + + return &this->public; +} + diff --git a/src/libcharon/sa/ikev1/task_manager_v1.h b/src/libcharon/sa/ikev1/task_manager_v1.h new file mode 100644 index 000000000..61e409bbe --- /dev/null +++ b/src/libcharon/sa/ikev1/task_manager_v1.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup task_manager_v1 task_manager_v1 + * @{ @ingroup ikev1 + */ + +#ifndef TASK_MANAGER_V1_H_ +#define TASK_MANAGER_V1_H_ + +typedef struct task_manager_v1_t task_manager_v1_t; + +#include + +/** + * Task manager, IKEv1 variant. + */ +struct task_manager_v1_t { + + /** + * Implements task_manager_t. + */ + task_manager_t task_manager; +}; + +/** + * Create an instance of the task manager. + * + * @param ike_sa IKE_SA to manage. + */ +task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa); + +#endif /** TASK_MANAGER_V1_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c new file mode 100644 index 000000000..954dea880 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "aggressive_mode.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_aggressive_mode_t private_aggressive_mode_t; + +/** + * Private members of a aggressive_mode_t task. + */ +struct private_aggressive_mode_t { + + /** + * Public methods and task_t interface. + */ + aggressive_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Common phase 1 helper class + */ + phase1_t *ph1; + + /** + * IKE config to establish + */ + ike_cfg_t *ike_cfg; + + /** + * Peer config to use + */ + peer_cfg_t *peer_cfg; + + /** + * selected IKE proposal + */ + proposal_t *proposal; + + /** + * Negotiated SA lifetime + */ + u_int32_t lifetime; + + /** + * Negotiated authentication method + */ + auth_method_t method; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_data; + + /** states of aggressive mode */ + enum { + AM_INIT, + AM_AUTH, + } state; +}; + +/** + * Set IKE_SA to established state + */ +static bool establish(private_aggressive_mode_t *this) +{ + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; +} + +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_aggressive_mode_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } + } + enumerator->destroy(enumerator); + + return err; +} + +/** + * Queue a task sending a notify in an INFORMATIONAL exchange + */ +static status_t send_notify(private_aggressive_mode_t *this, notify_type_t type) +{ + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + u_int64_t spi_i, spi_r; + chunk_t spi; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type); + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + notify->set_spi_data(notify, spi); + + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + this->ike_sa->flush_queue(this->ike_sa, + this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE); + return ALREADY_DONE; +} + +/** + * Queue a delete task if authentication failed as initiator + */ +static status_t send_delete(private_aggressive_mode_t *this) +{ + this->ike_sa->queue_task(this->ike_sa, + (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); + /* cancel all active tasks in favour of informational */ + this->ike_sa->flush_queue(this->ike_sa, + this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE); + return ALREADY_DONE; +} + +METHOD(task_t, build_i, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + switch (this->state) + { + case AM_INIT: + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + linked_list_t *proposals; + identification_t *id; + packet_t *packet; + u_int16_t group; + + DBG0(DBG_IKE, "initiating Aggressive Mode IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + + this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg); + if (this->method == AUTH_NONE) + { + DBG1(DBG_CFG, "configuration uses unsupported authentication"); + return FAILED; + } + this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, + FALSE); + if (!this->lifetime) + { /* fall back to rekey time of no rekey time configured */ + this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, + FALSE); + } + this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); + proposals = this->ike_cfg->get_proposals(this->ike_cfg); + sa_payload = sa_payload_create_from_proposals_v1(proposals, + this->lifetime, 0, this->method, MODE_NONE, FALSE, 0); + proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); + + message->add_payload(message, &sa_payload->payload_interface); + + group = this->ike_cfg->get_dh_group(this->ike_cfg); + if (group == MODP_NONE) + { + DBG1(DBG_IKE, "DH group selection failed"); + return FAILED; + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "DH group %N not supported", + diffie_hellman_group_names, group); + return FAILED; + } + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return FAILED; + } + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification(ID_V1, id); + this->id_data = id_payload->get_encoded(id_payload); + message->add_payload(message, &id_payload->payload_interface); + + /* pregenerate message to store SA payload */ + if (this->ike_sa->generate_message(this->ike_sa, message, + &packet) != SUCCESS) + { + DBG1(DBG_IKE, "pregenerating SA payload failed"); + return FAILED; + } + packet->destroy(packet); + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + DBG1(DBG_IKE, "SA payload invalid"); + return FAILED; + } + this->state = AM_AUTH; + return NEED_MORE; + } + case AM_AUTH: + { + if (!this->ph1->build_auth(this->ph1, this->method, message, + this->id_data)) + { + this->id_data = chunk_empty; + return send_notify(this, AUTHENTICATION_FAILED); + } + this->id_data = chunk_empty; + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + /* wait for XAUTH request */ + break; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + default: + if (charon->ike_sa_manager->check_uniqueness( + charon->ike_sa_manager, this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling Aggressive Mode due to " + "uniqueness policy"); + return send_notify(this, AUTHENTICATION_FAILED); + } + if (!establish(this)) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + break; + } + if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + switch (this->state) + { + case AM_INIT: + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id; + linked_list_t *list; + u_int16_t group; + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating a Aggressive Mode IKE_SA", + message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_sa->update_hosts(this->ike_sa, + message->get_destination(message), + message->get_source(message), TRUE); + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + this->method = sa_payload->get_auth_method(sa_payload); + this->lifetime = sa_payload->get_lifetime(sa_payload); + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + case AUTH_PSK: + if (!lib->settings->get_bool(lib->settings, "%s.i_dont_care" + "_about_security_and_use_aggressive_mode_psk", + FALSE, charon->name)) + { + DBG1(DBG_IKE, "Aggressive Mode PSK disabled for " + "security reasons"); + return send_notify(this, AUTHENTICATION_FAILED); + } + break; + default: + break; + } + + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDii payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + id = id_payload->get_identification(id_payload); + this->id_data = id_payload->get_encoded(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + this->peer_cfg = this->ph1->select_config(this->ph1, + this->method, TRUE, id); + if (!this->peer_cfg) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + + this->state = AM_AUTH; + if (has_notify_errors(this, message)) + { + return FAILED; + } + return NEED_MORE; + } + case AM_AUTH: + { + while (TRUE) + { + if (this->ph1->verify_auth(this->ph1, this->method, message, + this->id_data)) + { + break; + } + this->peer_cfg->destroy(this->peer_cfg); + this->peer_cfg = this->ph1->select_config(this->ph1, + this->method, TRUE, NULL); + if (!this->peer_cfg) + { + this->id_data = chunk_empty; + return send_delete(this); + } + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + } + this->id_data = chunk_empty; + + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids " + "IKE_SA, cancelling"); + return send_delete(this); + } + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + /* wait for XAUTH request */ + break; + default: + if (charon->ike_sa_manager->check_uniqueness( + charon->ike_sa_manager, this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling Aggressive Mode due to " + "uniqueness policy"); + return send_delete(this); + } + if (!establish(this)) + { + return send_delete(this); + } + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create( + this->ike_sa->get_id(this->ike_sa))); + break; + } + if (!this->ph1->has_pool(this->ph1, this->peer_cfg) && + this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + if (this->state == AM_AUTH) + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id; + + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + this->lifetime, 0, this->method, MODE_NONE, FALSE, 0); + message->add_payload(message, &sa_payload->payload_interface); + + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->create_hasher(this->ph1)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + return NEED_MORE; + } + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + if (this->state == AM_AUTH) + { + auth_method_t method; + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id, *cid; + linked_list_t *list; + u_int32_t lifetime; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + lifetime = sa_payload->get_lifetime(sa_payload); + if (lifetime != this->lifetime) + { + DBG1(DBG_IKE, "received lifetime %us does not match configured " + "lifetime %us", lifetime, this->lifetime); + } + this->lifetime = lifetime; + method = sa_payload->get_auth_method(sa_payload); + if (method != this->method) + { + DBG1(DBG_IKE, "received %N authentication, but configured %N, " + "continue with configured", auth_method_names, method, + auth_method_names, this->method); + } + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->create_hasher(this->ph1)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDir payload missing"); + return send_delete(this); + } + id = id_payload->get_identification(id_payload); + cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE); + if (cid && !id->matches(id, cid)) + { + DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid); + id->destroy(id); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_other_id(this->ike_sa, id); + + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_notify(this, AUTHENTICATION_FAILED); + } + + return NEED_MORE; + } + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_aggressive_mode_t *this) +{ + return TASK_AGGRESSIVE_MODE; +} + +METHOD(task_t, migrate, void, + private_aggressive_mode_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + chunk_free(&this->id_data); + + this->ike_sa = ike_sa; + this->state = AM_INIT; + this->peer_cfg = NULL; + this->proposal = NULL; + this->ph1 = phase1_create(ike_sa, this->initiator); +} + +METHOD(task_t, destroy, void, + private_aggressive_mode_t *this) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + chunk_free(&this->id_data); + free(this); +} + +/* + * Described in header. + */ +aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator) +{ + private_aggressive_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ph1 = phase1_create(ike_sa, initiator), + .initiator = initiator, + .state = AM_INIT, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.h b/src/libcharon/sa/ikev1/tasks/aggressive_mode.h new file mode 100644 index 000000000..d0666f41c --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup aggressive_mode aggressive_mode + * @{ @ingroup tasks_v1 + */ + +#ifndef AGGRESSIVE_MODE_H_ +#define AGGRESSIVE_MODE_H_ + +typedef struct aggressive_mode_t aggressive_mode_t; + +#include +#include +#include + +/** + * IKEv1 aggressive mode, establishes an IKE_SA without identity protection. + */ +struct aggressive_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new AGGRESSIVE_MODE task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task initiated locally + * @return task to handle by the task_manager + */ +aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** AGGRESSIVE_MODE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/informational.c b/src/libcharon/sa/ikev1/tasks/informational.c new file mode 100644 index 000000000..bda1d2afb --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/informational.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "informational.h" + +#include +#include +#include + +#include + +typedef struct private_informational_t private_informational_t; + +/** + * Private members of a informational_t task. + */ +struct private_informational_t { + + /** + * Public methods and task_t interface. + */ + informational_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Notify payload to send + */ + notify_payload_t *notify; + + /** + * Delete subtask + */ + task_t *del; +}; + +/** + * Cancel active quick mode after receiving an error + */ +static void cancel_quick_mode(private_informational_t *this) +{ + enumerator_t *enumerator; + task_t *task; + + enumerator = this->ike_sa->create_task_enumerator(this->ike_sa, + TASK_QUEUE_ACTIVE); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == TASK_QUICK_MODE) + { + this->ike_sa->flush_queue(this->ike_sa, TASK_QUEUE_ACTIVE); + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_informational_t *this, message_t *message) +{ + message->add_payload(message, &this->notify->payload_interface); + this->notify = NULL; + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_informational_t *this, message_t *message) +{ + enumerator_t *enumerator; + delete_payload_t *delete; + notify_payload_t *notify; + notify_type_t type; + payload_t *payload; + status_t status = SUCCESS; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY_V1: + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + + if (type == INITIAL_CONTACT_IKEV1) + { + this->ike_sa->set_condition(this->ike_sa, + COND_INIT_CONTACT_SEEN, TRUE); + } + else if (type == UNITY_LOAD_BALANCE) + { + host_t *redirect, *me; + chunk_t data; + + data = notify->get_notification_data(notify); + redirect = host_create_from_chunk(AF_INET, data, + IKEV2_UDP_PORT); + if (redirect) + { /* treat the redirect as reauthentication */ + DBG1(DBG_IKE, "received %N notify. redirected to %H", + notify_type_names, type, redirect); + /* Cisco boxes reject the first message from 4500 */ + me = this->ike_sa->get_my_host(this->ike_sa); + me->set_port(me, charon->socket->get_port( + charon->socket, FALSE)); + this->ike_sa->set_other_host(this->ike_sa, redirect); + this->ike_sa->reauth(this->ike_sa); + enumerator->destroy(enumerator); + return DESTROY_ME; + } + else + { + DBG1(DBG_IKE, "received %N notify, invalid address"); + } + } + else if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + if (this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) + { /* only critical during main mode */ + status = FAILED; + } + switch (type) + { + case INVALID_ID_INFORMATION: + case NO_PROPOSAL_CHOSEN: + cancel_quick_mode(this); + break; + default: + break; + } + break; + } + else + { + DBG1(DBG_IKE, "received %N notify", + notify_type_names, type); + } + continue; + case DELETE_V1: + if (!this->del) + { + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + this->del = (task_t*)isakmp_delete_create(this->ike_sa, + FALSE); + } + else + { + this->del = (task_t*)quick_delete_create(this->ike_sa, + PROTO_NONE, 0, FALSE, FALSE); + } + } + break; + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + + if (this->del && status == SUCCESS) + { + return this->del->process(this->del, message); + } + return status; +} + +METHOD(task_t, build_r, status_t, + private_informational_t *this, message_t *message) +{ + if (this->del) + { + return this->del->build(this->del, message); + } + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_informational_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_informational_t *this) +{ + return TASK_INFORMATIONAL; +} + +METHOD(task_t, migrate, void, + private_informational_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_informational_t *this) +{ + DESTROY_IF(this->notify); + DESTROY_IF(this->del); + free(this); +} + +/* + * Described in header. + */ +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify) +{ + private_informational_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .notify = notify, + ); + + if (notify) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/informational.h b/src/libcharon/sa/ikev1/tasks/informational.h new file mode 100644 index 000000000..52938ffbc --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/informational.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup informational informational + * @{ @ingroup tasks_v1 + */ + +#ifndef INFORMATIONAL_H_ +#define INFORMATIONAL_H_ + +typedef struct informational_t informational_t; + +#include +#include +#include +#include + +/** + * IKEv1 informational exchange, negotiates errors. + */ +struct informational_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new informational task. + * + * @param ike_sa IKE_SA this task works for + * @param notify notify to send as initiator, NULL if responder + * @return task to handle by the task_manager + */ +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify); + +#endif /** INFORMATIONAL_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c new file mode 100644 index 000000000..edad3b2fa --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_cert_post.h" + +#include +#include +#include +#include +#include +#include +#include + + +typedef struct private_isakmp_cert_post_t private_isakmp_cert_post_t; + +/** + * Private members of a isakmp_cert_post_t task. + */ +struct private_isakmp_cert_post_t { + + /** + * Public methods and task_t interface. + */ + isakmp_cert_post_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * States of ike cert pre + */ + enum { + CR_SA, + CR_KE, + CR_AUTH, + } state; +}; + +/** + * Check if we actually use certificates for authentication + */ +static bool use_certs(private_isakmp_cert_post_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool use = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + use = TRUE; + break; + default: + break; + } + break; + } + } + enumerator->destroy(enumerator); + + return use; +} + +/** + * Add certificates to message + */ +static void build_certs(private_isakmp_cert_post_t *this, message_t *message) +{ + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!peer_cfg) + { + return; + } + + switch (peer_cfg->get_cert_policy(peer_cfg)) + { + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: + { + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_rule_t type; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!cert) + { + break; + } + payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert); + if (!payload) + { + break; + } + DBG1(DBG_IKE, "sending end entity cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &cert)) + { + if (type == AUTH_RULE_IM_CERT) + { + payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert); + if (payload) + { + DBG1(DBG_IKE, "sending issuer cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + } + } + } + enumerator->destroy(enumerator); + } + } +} + +METHOD(task_t, build_i, status_t, + private_isakmp_cert_post_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + if (this->state == CR_AUTH) + { + build_certs(this, message); + return SUCCESS; + } + return NEED_MORE; + case AGGRESSIVE: + if (this->state == CR_AUTH) + { + build_certs(this, message); + return SUCCESS; + } + return NEED_MORE; + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_isakmp_cert_post_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_KE: + return NEED_MORE; + case CR_AUTH: + return NEED_MORE; + default: + return FAILED; + } + } + case AGGRESSIVE: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_isakmp_cert_post_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + switch (this->state) + { + case CR_SA: + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + build_certs(this, message); + return SUCCESS; + } + case AGGRESSIVE: + switch (this->state) + { + case CR_SA: + build_certs(this, message); + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_isakmp_cert_post_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + break; + } + case AGGRESSIVE: + { + if (this->state == CR_SA) + { + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_AUTH; + return NEED_MORE; + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_cert_post_t *this) +{ + return TASK_ISAKMP_CERT_POST; +} + +METHOD(task_t, migrate, void, + private_isakmp_cert_post_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->state = CR_SA; +} + +METHOD(task_t, destroy, void, + private_isakmp_cert_post_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_cert_post_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .state = CR_SA, + ); + if (initiator) + { + this->public.task.process = _process_i; + this->public.task.build = _build_i; + } + else + { + this->public.task.process = _process_r; + this->public.task.build = _build_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h new file mode 100644 index 000000000..3a155cb68 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_cert_post isakmp_cert_post + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_CERT_POST_H_ +#define ISAKMP_CERT_POST_H_ + +typedef struct isakmp_cert_post_t isakmp_cert_post_t; + +#include +#include +#include + +/** + * ISAKMP_CERT_POST, IKEv1 certificate processing after authentication. + */ +struct isakmp_cert_post_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new isakmp_cert_post task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return isakmp_cert_post task to handle by the task_manager + */ +isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_CERT_POST_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c new file mode 100644 index 000000000..d48484f09 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_cert_pre.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t; + +/** + * Private members of a isakmp_cert_pre_t task. + */ +struct private_isakmp_cert_pre_t { + + /** + * Public methods and task_t interface. + */ + isakmp_cert_pre_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Send certificate requests? + */ + bool send_req; + + /** next message we expect */ + enum { + CR_SA, + CR_KE, + CR_AUTH, + } state; +}; + +/** + * Find the CA certificate for a given certreq payload + */ +static certificate_t* find_certificate(private_isakmp_cert_pre_t *this, + certreq_payload_t *certreq) +{ + identification_t *id; + certificate_t *cert; + + if (certreq->get_cert_type(certreq) != CERT_X509) + { + DBG1(DBG_IKE, "%N CERTREQ not supported - ignored", + certificate_type_names, certreq->get_cert_type(certreq)); + return NULL; + } + id = certreq->get_dn(certreq); + if (!id) + { + DBG1(DBG_IKE, "ignoring certificate request without data", + certificate_type_names, certreq->get_cert_type(certreq)); + return NULL; + } + cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE); + if (cert) + { + DBG1(DBG_IKE, "received cert request for '%Y'", + cert->get_subject(cert)); + } + else + { + DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id); + } + id->destroy(id); + + return cert; +} + +/** + * read certificate requests + */ +static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case CERTIFICATE_REQUEST_V1: + { + certificate_t *cert; + + this->ike_sa->set_condition(this->ike_sa, + COND_CERTREQ_SEEN, TRUE); + cert = find_certificate(this, (certreq_payload_t*)payload); + if (cert) + { + auth->add(auth, AUTH_RULE_CA_CERT, cert); + } + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Import receuved certificates + */ +static void process_certs(private_isakmp_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + bool first = TRUE; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CERTIFICATE_V1) + { + cert_payload_t *cert_payload; + cert_encoding_t encoding; + certificate_t *cert; + + cert_payload = (cert_payload_t*)payload; + encoding = cert_payload->get_cert_encoding(cert_payload); + + switch (encoding) + { + case ENC_X509_SIGNATURE: + { + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + if (first) + { /* the first is an end entity certificate */ + DBG1(DBG_IKE, "received end entity cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); + first = FALSE; + } + else + { + DBG1(DBG_IKE, "received issuer cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_IM_CERT, cert); + } + } + break; + } + case ENC_CRL: + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + DBG1(DBG_IKE, "received CRL \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert); + } + break; + case ENC_PKCS7_WRAPPED_X509: + case ENC_PGP: + case ENC_DNS_SIGNED_KEY: + case ENC_KERBEROS_TOKEN: + case ENC_ARL: + case ENC_SPKI: + case ENC_X509_ATTRIBUTE: + case ENC_RAW_RSA_KEY: + case ENC_X509_HASH_AND_URL_BUNDLE: + case ENC_OCSP_CONTENT: + default: + DBG1(DBG_ENC, "certificate encoding %N not supported", + cert_encoding_names, encoding); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Add the subject of a CA certificate a message + */ +static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message, + certificate_t *cert) +{ + if (cert->get_type(cert) == CERT_X509) + { + x509_t *x509 = (x509_t*)cert; + + if (x509->get_flags(x509) & X509_CA) + { + DBG1(DBG_IKE, "sending cert request for \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*) + certreq_payload_create_dn(cert->get_subject(cert))); + } + } +} + +/** + * Add auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs(private_isakmp_cert_pre_t *this, + auth_cfg_t *auth, message_t *message) +{ + enumerator_t *enumerator; + auth_rule_t type; + void *value; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTH_RULE_CA_CERT: + add_certreq(this, message, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Build certificate requests + */ +static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + certificate_t *cert; + auth_cfg_t *auth; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + if (!ike_cfg->send_certreq(ike_cfg)) + { + return; + } + /* check if we require a specific CA for that peer */ + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + if (enumerator->enumerate(enumerator, &auth)) + { + add_certreqs(this, auth, message); + } + enumerator->destroy(enumerator); + } + if (!message->get_payload(message, CERTIFICATE_REQUEST_V1)) + { + /* otherwise add all trusted CA certificates */ + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_ANY, KEY_ANY, NULL, TRUE); + while (enumerator->enumerate(enumerator, &cert)) + { + add_certreq(this, message, cert); + } + enumerator->destroy(enumerator); + } +} + +/** + * Check if we actually use certificates for authentication + */ +static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool use = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + if (!this->initiator) + { + this->send_req = FALSE; + } + /* FALL */ + case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + use = TRUE; + break; + default: + break; + } + break; + } + } + enumerator->destroy(enumerator); + + return use; +} + +/** + * Check if we should send a certificate request + */ +static bool send_certreq(private_isakmp_cert_pre_t *this) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth; + bool req = FALSE; + auth_class_t class; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + if (enumerator->enumerate(enumerator, &auth)) + { + class = (intptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + if (class == AUTH_CLASS_PUBKEY) + { + req = TRUE; + } + } + enumerator->destroy(enumerator); + } + return req; +} + +METHOD(task_t, build_i, status_t, + private_isakmp_cert_pre_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + if (this->state == CR_AUTH) + { + build_certreqs(this, message); + } + return NEED_MORE; + case AGGRESSIVE: + if (this->state == CR_SA) + { + if (send_certreq(this)) + { + build_certreqs(this, message); + } + } + return NEED_MORE; + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_isakmp_cert_pre_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_KE: + process_certreqs(this, message); + return NEED_MORE; + case CR_AUTH: + process_certreqs(this, message); + process_certs(this, message); + return SUCCESS; + default: + return FAILED; + } + } + case AGGRESSIVE: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + process_certreqs(this, message); + return NEED_MORE; + case CR_AUTH: + process_certs(this, message); + return SUCCESS; + default: + return FAILED; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_isakmp_cert_pre_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + switch (this->state) + { + case CR_SA: + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + if (this->send_req) + { + build_certreqs(this, message); + } + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return NEED_MORE; + default: + return FAILED; + } + case AGGRESSIVE: + switch (this->state) + { + case CR_SA: + if (this->send_req) + { + build_certreqs(this, message); + } + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_isakmp_cert_pre_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + process_certreqs(this, message); + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + process_certs(this, message); + return SUCCESS; + default: + return FAILED; + } + break; + } + case AGGRESSIVE: + { + if (!use_certs(this, message)) + { + return SUCCESS; + } + process_certreqs(this, message); + process_certs(this, message); + this->state = CR_AUTH; + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_cert_pre_t *this) +{ + return TASK_ISAKMP_CERT_PRE; +} + +METHOD(task_t, migrate, void, + private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->state = CR_SA; + this->send_req = TRUE; +} + +METHOD(task_t, destroy, void, + private_isakmp_cert_pre_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_cert_pre_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .state = CR_SA, + .send_req = TRUE, + ); + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h new file mode 100644 index 000000000..8e1a94b97 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_cert_pre isakmp_cert_pre + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_CERT_PRE_H_ +#define ISAKMP_CERT_PRE_H_ + +typedef struct isakmp_cert_pre_t isakmp_cert_pre_t; + +#include +#include +#include + +/** + * ISAKMP_CERT_PRE task, IKEv1 certificate processing before authentication. + */ +struct isakmp_cert_pre_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ISAKMP_CERT_PRE task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return isakmp_cert_pre task to handle by the task_manager + */ +isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_CERT_PRE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_delete.c b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c new file mode 100644 index 000000000..0640d13b1 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_delete.h" + +#include +#include + +typedef struct private_isakmp_delete_t private_isakmp_delete_t; + +/** + * Private members of a isakmp_delete_t task. + */ +struct private_isakmp_delete_t { + + /** + * Public methods and task_t interface. + */ + isakmp_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; +}; + +METHOD(task_t, build_i, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + delete_payload_t *delete_payload; + ike_sa_id_t *id; + + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE); + id = this->ike_sa->get_id(this->ike_sa); + delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id), + id->get_responder_spi(id)); + message->add_payload(message, (payload_t*)delete_payload); + + DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; +} + +METHOD(task_t, build_r, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_delete_t *this) +{ + return TASK_ISAKMP_DELETE; +} + +METHOD(task_t, migrate, void, + private_isakmp_delete_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_isakmp_delete_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_delete.h b/src/libcharon/sa/ikev1/tasks/isakmp_delete.h new file mode 100644 index 000000000..1a7a62207 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_delete.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_delete isakmp_delete + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_DELETE_H_ +#define ISAKMP_DELETE_H_ + +typedef struct isakmp_delete_t isakmp_delete_t; + +#include +#include +#include + +/** + * Task of type ISAKMP_DELETE, delete an IKEv1 IKE_SA. + */ +struct isakmp_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new isakmp_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if we initiate the delete + * @return isakmp_delete task to handle by the task_manager + */ +isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c new file mode 100644 index 000000000..a3395a043 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_dpd.h" + +#include +#include + +typedef struct private_isakmp_dpd_t private_isakmp_dpd_t; + +/** + * Private members of a isakmp_dpd_t task. + */ +struct private_isakmp_dpd_t { + + /** + * Public methods and task_t interface. + */ + isakmp_dpd_t public; + + /** + * Sequence number. + */ + u_int32_t seqnr; + + /** + * DPD notify type + */ + notify_type_t type; + + /** + * IKE SA we are serving. + */ + ike_sa_t *ike_sa; +}; + +METHOD(task_t, build, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + u_int64_t spi_i, spi_r; + u_int32_t seqnr; + chunk_t spi; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, this->type); + seqnr = htonl(this->seqnr); + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + + notify->set_spi_data(notify, spi); + notify->set_notification_data(notify, chunk_from_thing(seqnr)); + + message->add_payload(message, (payload_t*)notify); + + return SUCCESS; +} + +METHOD(task_t, process, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + /* done in task manager */ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_dpd_t *this) +{ + return TASK_ISAKMP_DPD; +} + +METHOD(task_t, migrate, void, + private_isakmp_dpd_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_isakmp_dpd_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_type_t type, + u_int32_t seqnr) +{ + private_isakmp_dpd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .build = _build, + .process = _process, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .seqnr = seqnr, + .type = type, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h new file mode 100644 index 000000000..06a0175eb --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_dpd isakmp_dpd + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_DPD_H_ +#define ISAKMP_DPD_H_ + +typedef struct isakmp_dpd_t isakmp_dpd_t; + +#include +#include +#include + +/** + * IKEv1 dead peer detection task. + */ +struct isakmp_dpd_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ISAKMP_DPD task. + * + * @param ike_sa associated IKE_SA + * @param type DPD notify to use, DPD_R_U_THERE | DPD_R_U_THERE_ACK + * @param seqnr DPD sequence number to use/expect + * @return ISAKMP_DPD task to handle by the task_manager + */ +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_type_t type, + u_int32_t seqnr); + +#endif /** ISAKMP_DPD_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c new file mode 100644 index 000000000..50bf1612d --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2006-2011 Tobias Brunner, + * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006 Daniel Roethlisberger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_natd.h" + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct private_isakmp_natd_t private_isakmp_natd_t; + +/** + * Private members of a ike_natt_t task. + */ +struct private_isakmp_natd_t { + + /** + * Public interface. + */ + isakmp_natd_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Keymat derivation (from SA) + */ + keymat_v1_t *keymat; + + /** + * Did we process any NAT detection payloads for a source address? + */ + bool src_seen; + + /** + * Did we process any NAT detection payloads for a destination address? + */ + bool dst_seen; + + /** + * Have we found a matching source address NAT hash? + */ + bool src_matched; + + /** + * Have we found a matching destination address NAT hash? + */ + bool dst_matched; +}; + +/** + * Build NAT detection hash for a host. + */ +static chunk_t generate_natd_hash(private_isakmp_natd_t *this, + ike_sa_id_t *ike_sa_id, host_t *host) +{ + hasher_t *hasher; + chunk_t natd_chunk, natd_hash; + u_int64_t spi_i, spi_r; + u_int16_t port; + + hasher = this->keymat->get_hasher(this->keymat); + if (!hasher) + { + DBG1(DBG_IKE, "no hasher available to build NAT-D payload"); + return chunk_empty; + } + + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + port = htons(host->get_port(host)); + + /* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */ + natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i), + chunk_from_thing(spi_r), host->get_address(host), + chunk_from_thing(port)); + if (!hasher->allocate_hash(hasher, natd_chunk, &natd_hash)) + { + DBG1(DBG_IKE, "creating NAT-D payload hash failed"); + return chunk_empty; + } + DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk); + DBG3(DBG_IKE, "natd_hash %B", &natd_hash); + + return natd_hash; +} + +/** + * Build a faked NAT-D payload to enforce UDP encapsulation. + */ +static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this) +{ + hasher_t *hasher; + chunk_t chunk; + rng_t *rng; + + hasher = this->keymat->get_hasher(this->keymat); + if (!hasher) + { + DBG1(DBG_IKE, "no hasher available to build NAT-D payload"); + return chunk_empty; + } + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng || + !rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk)) + { + DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake"); + DESTROY_IF(rng); + return chunk_empty; + } + rng->destroy(rng); + return chunk; +} + +/** + * Build a NAT-D payload. + */ +static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src, + host_t *host) +{ + hash_payload_t *payload; + ike_cfg_t *config; + chunk_t hash; + + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (src && config->force_encap(config)) + { + hash = generate_natd_hash_faked(this); + } + else + { + ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa); + hash = generate_natd_hash(this, ike_sa_id, host); + } + if (!hash.len) + { + return NULL; + } + payload = hash_payload_create(NAT_D_V1); + payload->set_hash(payload, hash); + chunk_free(&hash); + return payload; +} + +/** + * Add NAT-D payloads to the message. + */ +static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message) +{ + hash_payload_t *payload; + host_t *host; + + /* destination has to be added first */ + host = message->get_destination(message); + payload = build_natd_payload(this, FALSE, host); + if (payload) + { + message->add_payload(message, (payload_t*)payload); + } + + /* source is added second, compared with IKEv2 we always know the source, + * as these payloads are added in the second Phase 1 exchange or the + * response to the first */ + host = message->get_source(message); + payload = build_natd_payload(this, TRUE, host); + if (payload) + { + message->add_payload(message, (payload_t*)payload); + } +} + +/** + * Read NAT-D payloads from message and evaluate them. + */ +static void process_payloads(private_isakmp_natd_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + hash_payload_t *hash_payload; + chunk_t hash, src_hash, dst_hash; + ike_sa_id_t *ike_sa_id; + host_t *me, *other; + ike_cfg_t *config; + + /* precompute hashes for incoming NAT-D comparison */ + ike_sa_id = message->get_ike_sa_id(message); + me = message->get_destination(message); + other = message->get_source(message); + dst_hash = generate_natd_hash(this, ike_sa_id, me); + src_hash = generate_natd_hash(this, ike_sa_id, other); + + DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); + DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) != NAT_D_V1) + { + continue; + } + hash_payload = (hash_payload_t*)payload; + if (!this->dst_seen) + { /* the first NAT-D payload contains the destination hash */ + this->dst_seen = TRUE; + hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_IKE, "received dst_hash %B", &hash); + if (chunk_equals(hash, dst_hash)) + { + this->dst_matched = TRUE; + } + continue; + } + /* the other NAT-D payloads contain source hashes */ + this->src_seen = TRUE; + if (!this->src_matched) + { + hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_IKE, "received src_hash %B", &hash); + if (chunk_equals(hash, src_hash)) + { + this->src_matched = TRUE; + } + } + } + enumerator->destroy(enumerator); + + chunk_free(&src_hash); + chunk_free(&dst_hash); + + if (this->src_seen && this->dst_seen) + { + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (this->dst_matched && this->src_matched && + config->force_encap(config)) + { + this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE); + } + } +} + +METHOD(task_t, build_i, status_t, + private_isakmp_natd_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + switch (message->get_exchange_type(message)) + { + case AGGRESSIVE: + { /* add NAT-D payloads to the second request, already processed + * those by the responder contained in the first response */ + result = SUCCESS; + /* fall */ + } + case ID_PROT: + { /* add NAT-D payloads to the second request, need to process + * those by the responder contained in the second response */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + add_natd_payloads(this, message); + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_isakmp_natd_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) + { /* we didn't receive VIDs inidcating support for NAT-T */ + return SUCCESS; + } + + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { /* process NAT-D payloads in the second response, added them in the + * second request already, so we're done afterwards */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + result = SUCCESS; + /* fall */ + } + case AGGRESSIVE: + { /* process NAT-D payloads in the first response, add them in the + * following second request */ + process_payloads(this, message); + + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + this->ike_sa->float_ports(this->ike_sa); + } + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_isakmp_natd_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) + { /* we didn't receive VIDs indicating NAT-T support */ + return SUCCESS; + } + + switch (message->get_exchange_type(message)) + { + case AGGRESSIVE: + { /* proccess NAT-D payloads in the second request, already added ours + * in the first response */ + result = SUCCESS; + /* fall */ + } + case ID_PROT: + { /* process NAT-D payloads in the second request, need to add ours + * to the second response */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + process_payloads(this, message); + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, build_r, status_t, + private_isakmp_natd_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { /* add NAT-D payloads to second response, already processed those + * contained in the second request */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + add_natd_payloads(this, message); + return SUCCESS; + } + case AGGRESSIVE: + { /* add NAT-D payloads to the first response, process those contained + * in the following second request */ + add_natd_payloads(this, message); + return NEED_MORE; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_natd_t *this) +{ + return TASK_ISAKMP_NATD; +} + +METHOD(task_t, migrate, void, + private_isakmp_natd_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + this->src_seen = FALSE; + this->dst_seen = FALSE; + this->src_matched = FALSE; + this->dst_matched = FALSE; +} + +METHOD(task_t, destroy, void, + private_isakmp_natd_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_natd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_natd.h b/src/libcharon/sa/ikev1/tasks/isakmp_natd.h new file mode 100644 index 000000000..63947fc73 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_natd isakmp_natd + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_NATD_H_ +#define ISAKMP_NATD_H_ + +typedef struct isakmp_natd_t isakmp_natd_t; + +#include +#include +#include + +/** + * Task of type ISAKMP_NATD, detects NAT situation in IKEv1 Phase 1. + */ +struct isakmp_natd_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ISAKMP_NATD task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return isakmp_natd task to handle by the task_manager + */ +isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_NATD_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c new file mode 100644 index 000000000..4fd0ef39b --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_vendor.h" + +#include +#include + +typedef struct private_isakmp_vendor_t private_isakmp_vendor_t; + +/** + * Private data of an isakmp_vendor_t object. + */ +struct private_isakmp_vendor_t { + + /** + * Public isakmp_vendor_t interface. + */ + isakmp_vendor_t public; + + /** + * Associated IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * Are we the inititator of this task + */ + bool initiator; +}; + +/** + * IKEv1 Vendor ID database + */ +static struct { + /* Description */ + char *desc; + /* extension flag negotiated with vendor ID, if any */ + ike_extension_t extension; + /* send yourself? */ + bool send; + /* length of vendor ID string */ + int len; + /* vendor ID string */ + char *id; +} vendor_ids[] = { + + /* strongSwan MD5("strongSwan") */ + { "strongSwan", EXT_STRONGSWAN, FALSE, 16, + "\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"}, + + /* XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") */ + { "XAuth", EXT_XAUTH, TRUE, 8, + "\x09\x00\x26\x89\xdf\xd6\xb7\x12"}, + + /* NAT-Traversal, MD5("RFC 3947") */ + { "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16, + "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"}, + + /* Dead peer detection, RFC 3706 */ + { "DPD", EXT_DPD, TRUE, 16, + "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"}, + + { "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16, + "\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"}, + + { "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16, + "\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"}, + + { "draft-ietf-ipsec-nat-t-ike", 0, FALSE, 16, + "\x4d\xf3\x79\x28\xe9\xfc\x4f\xd1\xb3\x26\x21\x70\xd5\x15\xc6\x62"}, + + { "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16, + "\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"}, + + { "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16, + "\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"}, + + { "draft-ietf-ipsec-nat-t-ike-02\\n", 0, FALSE, 16, + "\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"}, + + { "draft-ietf-ipsec-nat-t-ike-03", 0, FALSE, 16, + "\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"}, + + { "draft-ietf-ipsec-nat-t-ike-04", 0, FALSE, 16, + "\x99\x09\xb6\x4e\xed\x93\x7c\x65\x73\xde\x52\xac\xe9\x52\xfa\x6b"}, + + { "draft-ietf-ipsec-nat-t-ike-05", 0, FALSE, 16, + "\x80\xd0\xbb\x3d\xef\x54\x56\x5e\xe8\x46\x45\xd4\xc8\x5c\xe3\xee"}, + + { "draft-ietf-ipsec-nat-t-ike-06", 0, FALSE, 16, + "\x4d\x1e\x0e\x13\x6d\xea\xfa\x34\xc4\xf3\xea\x9f\x02\xec\x72\x85"}, + + { "draft-ietf-ipsec-nat-t-ike-07", 0, FALSE, 16, + "\x43\x9b\x59\xf8\xba\x67\x6c\x4c\x77\x37\xae\x22\xea\xb8\xf5\x82"}, + + { "draft-ietf-ipsec-nat-t-ike-08", 0, FALSE, 16, + "\x8f\x8d\x83\x82\x6d\x24\x6b\x6f\xc7\xa8\xa6\xa4\x28\xc1\x1d\xe8"}, + + { "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16, + "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"}, +}; + +METHOD(task_t, build, status_t, + private_isakmp_vendor_t *this, message_t *message) +{ + vendor_id_payload_t *vid_payload; + bool strongswan, cisco_unity; + int i; + + strongswan = lib->settings->get_bool(lib->settings, + "%s.send_vendor_id", FALSE, charon->name); + cisco_unity = lib->settings->get_bool(lib->settings, + "%s.cisco_unity", FALSE, charon->name); + for (i = 0; i < countof(vendor_ids); i++) + { + if (vendor_ids[i].send || + (vendor_ids[i].extension == EXT_STRONGSWAN && strongswan) || + (vendor_ids[i].extension == EXT_CISCO_UNITY && cisco_unity)) + { + vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1, + chunk_clone(chunk_create(vendor_ids[i].id, vendor_ids[i].len))); + message->add_payload(message, &vid_payload->payload_interface); + } + } + return this->initiator ? NEED_MORE : SUCCESS; +} + +METHOD(task_t, process, status_t, + private_isakmp_vendor_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + int i; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == VENDOR_ID_V1) + { + vendor_id_payload_t *vid; + bool found = FALSE; + chunk_t data; + + vid = (vendor_id_payload_t*)payload; + data = vid->get_data(vid); + + for (i = 0; i < countof(vendor_ids); i++) + { + if (chunk_equals(data, chunk_create(vendor_ids[i].id, + vendor_ids[i].len))) + { + DBG1(DBG_IKE, "received %s vendor ID", vendor_ids[i].desc); + if (vendor_ids[i].extension) + { + this->ike_sa->enable_extension(this->ike_sa, + vendor_ids[i].extension); + } + found = TRUE; + } + } + if (!found) + { + DBG1(DBG_ENC, "received unknown vendor ID: %#B", &data); + } + } + } + enumerator->destroy(enumerator); + + return this->initiator ? SUCCESS : NEED_MORE; +} + +METHOD(task_t, migrate, void, + private_isakmp_vendor_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_vendor_t *this) +{ + return TASK_ISAKMP_VENDOR; +} + +METHOD(task_t, destroy, void, + private_isakmp_vendor_t *this) +{ + free(this); +} + +/** + * See header + */ +isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_vendor_t *this; + + INIT(this, + .public = { + .task = { + .build = _build, + .process = _process, + .migrate = _migrate, + .get_type = _get_type, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.h b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.h new file mode 100644 index 000000000..91891085b --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_vendor isakmp_vendor + * @{ @ingroup tasks_v1 + */ + +#ifndef ISAKMP_VENDOR_H_ +#define ISAKMP_VENDOR_H_ + +typedef struct isakmp_vendor_t isakmp_vendor_t; + +#include +#include +#include + +/** + * Vendor ID processing task for IKEv1. + */ +struct isakmp_vendor_t { + + /** + * Implements task interface. + */ + task_t task; +}; + +/** + * Create a isakmp_vendor instance. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + */ +isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_VENDOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c new file mode 100644 index 000000000..9ccf9abf5 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -0,0 +1,735 @@ +/* + * Copyright (C) 2011-2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "main_mode.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_main_mode_t private_main_mode_t; + +/** + * Private members of a main_mode_t task. + */ +struct private_main_mode_t { + + /** + * Public methods and task_t interface. + */ + main_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Common phase 1 helper class + */ + phase1_t *ph1; + + /** + * IKE config to establish + */ + ike_cfg_t *ike_cfg; + + /** + * Peer config to use + */ + peer_cfg_t *peer_cfg; + + /** + * selected IKE proposal + */ + proposal_t *proposal; + + /** + * Negotiated SA lifetime + */ + u_int32_t lifetime; + + /** + * Negotiated authentication method + */ + auth_method_t method; + + /** states of main mode */ + enum { + MM_INIT, + MM_SA, + MM_KE, + MM_AUTH, + } state; +}; + +/** + * Set IKE_SA to established state + */ +static bool establish(private_main_mode_t *this) +{ + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; +} + +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_main_mode_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else if (type == INITIAL_CONTACT_IKEV1) + { + if (!this->initiator && this->state == MM_AUTH) + { + /* If authenticated and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. + * The delete takes place when the SA is checked in due + * to other id not known until the 3rd message.*/ + this->ike_sa->set_condition(this->ike_sa, + COND_INIT_CONTACT_SEEN, TRUE); + } + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } + } + enumerator->destroy(enumerator); + + return err; +} + +/** + * Queue a task sending a notify in an INFORMATIONAL exchange + */ +static status_t send_notify(private_main_mode_t *this, notify_type_t type) +{ + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + u_int64_t spi_i, spi_r; + chunk_t spi; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type); + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + notify->set_spi_data(notify, spi); + + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + this->ike_sa->flush_queue(this->ike_sa, + this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE); + return ALREADY_DONE; +} + +/** + * Queue a delete task if authentication failed as initiator + */ +static status_t send_delete(private_main_mode_t *this) +{ + this->ike_sa->queue_task(this->ike_sa, + (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); + /* cancel all active tasks in favour of informational */ + this->ike_sa->flush_queue(this->ike_sa, + this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE); + return ALREADY_DONE; +} + +METHOD(task_t, build_i, status_t, + private_main_mode_t *this, message_t *message) +{ + switch (this->state) + { + case MM_INIT: + { + sa_payload_t *sa_payload; + linked_list_t *proposals; + packet_t *packet; + + DBG0(DBG_IKE, "initiating Main Mode IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + + this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg); + if (this->method == AUTH_NONE) + { + DBG1(DBG_CFG, "configuration uses unsupported authentication"); + return FAILED; + } + this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, + FALSE); + if (!this->lifetime) + { /* fall back to rekey time of no rekey time configured */ + this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, + FALSE); + } + this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); + proposals = this->ike_cfg->get_proposals(this->ike_cfg); + sa_payload = sa_payload_create_from_proposals_v1(proposals, + this->lifetime, 0, this->method, MODE_NONE, FALSE, 0); + proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); + + message->add_payload(message, &sa_payload->payload_interface); + + /* pregenerate message to store SA payload */ + if (this->ike_sa->generate_message(this->ike_sa, message, + &packet) != SUCCESS) + { + DBG1(DBG_IKE, "pregenerating SA payload failed"); + return FAILED; + } + packet->destroy(packet); + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + return FAILED; + } + + this->state = MM_SA; + return NEED_MORE; + } + case MM_SA: + { + u_int16_t group; + + if (!this->ph1->create_hasher(this->ph1)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + this->state = MM_KE; + return NEED_MORE; + } + case MM_KE: + { + id_payload_t *id_payload; + identification_t *id; + + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + + this->state = MM_AUTH; + return NEED_MORE; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_main_mode_t *this, message_t *message) +{ + switch (this->state) + { + case MM_INIT: + { + linked_list_t *list; + sa_payload_t *sa_payload; + bool private; + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating a Main Mode IKE_SA", + message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_sa->update_hosts(this->ike_sa, + message->get_destination(message), + message->get_source(message), TRUE); + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + list = sa_payload->get_proposals(sa_payload); + private = this->ike_sa->supports_extension(this->ike_sa, + EXT_STRONGSWAN); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, private); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + this->method = sa_payload->get_auth_method(sa_payload); + this->lifetime = sa_payload->get_lifetime(sa_payload); + + this->state = MM_SA; + return NEED_MORE; + } + case MM_SA: + { + u_int16_t group; + + if (!this->ph1->create_hasher(this->ph1)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + this->state = MM_KE; + return NEED_MORE; + } + case MM_KE: + { + id_payload_t *id_payload; + identification_t *id; + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDii payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + id = id_payload->get_identification(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + + while (TRUE) + { + DESTROY_IF(this->peer_cfg); + this->peer_cfg = this->ph1->select_config(this->ph1, + this->method, FALSE, id); + if (!this->peer_cfg) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + + if (this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + break; + } + } + + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_notify(this, AUTHENTICATION_FAILED); + } + + this->state = MM_AUTH; + if (has_notify_errors(this, message)) + { + return FAILED; + } + return NEED_MORE; + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_main_mode_t *this, message_t *message) +{ + switch (this->state) + { + case MM_SA: + { + sa_payload_t *sa_payload; + + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + this->lifetime, 0, this->method, MODE_NONE, FALSE, 0); + message->add_payload(message, &sa_payload->payload_interface); + + return NEED_MORE; + } + case MM_KE: + { + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + return NEED_MORE; + } + case MM_AUTH: + { + id_payload_t *id_payload; + identification_t *id; + + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + /* wait for XAUTH request */ + break; + default: + if (charon->ike_sa_manager->check_uniqueness( + charon->ike_sa_manager, this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling Main Mode due to uniqueness " + "policy"); + return send_notify(this, AUTHENTICATION_FAILED); + } + if (!establish(this)) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create( + this->ike_sa->get_id(this->ike_sa))); + break; + } + if (!this->ph1->has_pool(this->ph1, this->peer_cfg) && + this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_main_mode_t *this, message_t *message) +{ + switch (this->state) + { + case MM_SA: + { + linked_list_t *list; + sa_payload_t *sa_payload; + auth_method_t method; + u_int32_t lifetime; + bool private; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + list = sa_payload->get_proposals(sa_payload); + private = this->ike_sa->supports_extension(this->ike_sa, + EXT_STRONGSWAN); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, private); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + lifetime = sa_payload->get_lifetime(sa_payload); + if (lifetime != this->lifetime) + { + DBG1(DBG_IKE, "received lifetime %us does not match configured " + "lifetime %us", lifetime, this->lifetime); + } + this->lifetime = lifetime; + method = sa_payload->get_auth_method(sa_payload); + if (method != this->method) + { + DBG1(DBG_IKE, "received %N authentication, but configured %N, " + "continue with configured", auth_method_names, method, + auth_method_names, this->method); + } + return NEED_MORE; + } + case MM_KE: + { + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + return NEED_MORE; + } + case MM_AUTH: + { + id_payload_t *id_payload; + identification_t *id, *cid; + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDir payload missing"); + return send_delete(this); + } + id = id_payload->get_identification(id_payload); + cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE); + if (cid && !id->matches(id, cid)) + { + DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid); + id->destroy(id); + return send_delete(this); + } + this->ike_sa->set_other_id(this->ike_sa, id); + + if (!this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_delete(this); + } + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_delete(this); + } + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + /* wait for XAUTH request */ + break; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + default: + if (charon->ike_sa_manager->check_uniqueness( + charon->ike_sa_manager, this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling Main Mode due to uniqueness " + "policy"); + return send_delete(this); + } + if (!establish(this)) + { + return send_delete(this); + } + break; + } + if (this->ph1->has_virtual_ip(this->ph1, this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_main_mode_t *this) +{ + return TASK_MAIN_MODE; +} + +METHOD(task_t, migrate, void, + private_main_mode_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + + this->ike_sa = ike_sa; + this->state = MM_INIT; + this->peer_cfg = NULL; + this->proposal = NULL; + this->ph1 = phase1_create(ike_sa, this->initiator); +} + +METHOD(task_t, destroy, void, + private_main_mode_t *this) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + free(this); +} + +/* + * Described in header. + */ +main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator) +{ + private_main_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ph1 = phase1_create(ike_sa, initiator), + .initiator = initiator, + .state = MM_INIT, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.h b/src/libcharon/sa/ikev1/tasks/main_mode.h new file mode 100644 index 000000000..141701f75 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/main_mode.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup main_mode main_mode + * @{ @ingroup tasks_v1 + */ + +#ifndef MAIN_MODE_H_ +#define MAIN_MODE_H_ + +typedef struct main_mode_t main_mode_t; + +#include +#include +#include + +/** + * IKEv1 main mode, establishes a mainmode including authentication. + */ +struct main_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new main_mode task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task initiated locally + * @return task to handle by the task_manager + */ +main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** MAIN_MODE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c new file mode 100644 index 000000000..ce897727a --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/mode_config.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "mode_config.h" + +#include +#include +#include + +typedef struct private_mode_config_t private_mode_config_t; + +/** + * Private members of a mode_config_t task. + */ +struct private_mode_config_t { + + /** + * Public methods and task_t interface. + */ + mode_config_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Received list of virtual IPs, host_t* + */ + linked_list_t *vips; + + /** + * list of attributes requested and its handler, entry_t + */ + linked_list_t *requested; + + /** + * Identifier to include in response + */ + u_int16_t identifier; +}; + +/** + * Entry for a requested attribute and the requesting handler + */ +typedef struct { + /** attribute requested */ + configuration_attribute_type_t type; + /** handler requesting this attribute */ + attribute_handler_t *handler; +} entry_t; + +/** + * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip + */ +static configuration_attribute_t *build_vip(host_t *vip) +{ + configuration_attribute_type_t type; + chunk_t chunk, prefix; + + if (vip->get_family(vip) == AF_INET) + { + type = INTERNAL_IP4_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + chunk = vip->get_address(vip); + } + } + else + { + type = INTERNAL_IP6_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + prefix = chunk_alloca(1); + *prefix.ptr = 64; + chunk = vip->get_address(vip); + chunk = chunk_cata("cc", chunk, prefix); + } + } + return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, chunk); +} + +/** + * Handle a received attribute as initiator + */ +static void handle_attribute(private_mode_config_t *this, + configuration_attribute_t *ca) +{ + attribute_handler_t *handler = NULL; + enumerator_t *enumerator; + entry_t *entry; + + /* find the handler which requested this attribute */ + enumerator = this->requested->create_enumerator(this->requested); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->type == ca->get_type(ca)) + { + handler = entry->handler; + this->requested->remove_at(this->requested, enumerator); + free(entry); + break; + } + } + enumerator->destroy(enumerator); + + /* and pass it to the handle function */ + handler = hydra->attributes->handle(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), handler, + ca->get_type(ca), ca->get_chunk(ca)); + if (handler) + { + this->ike_sa->add_configuration_attribute(this->ike_sa, + handler, ca->get_type(ca), ca->get_chunk(ca)); + } +} + +/** + * process a single configuration attribute + */ +static void process_attribute(private_mode_config_t *this, + configuration_attribute_t *ca) +{ + host_t *ip; + chunk_t addr; + int family = AF_INET6; + + switch (ca->get_type(ca)) + { + case INTERNAL_IP4_ADDRESS: + family = AF_INET; + /* fall */ + case INTERNAL_IP6_ADDRESS: + { + addr = ca->get_chunk(ca); + if (addr.len == 0) + { + ip = host_create_any(family); + } + else + { + /* skip prefix byte in IPv6 payload*/ + if (family == AF_INET6) + { + addr.len--; + } + ip = host_create_from_chunk(family, addr, 0); + } + if (ip) + { + this->vips->insert_last(this->vips, ip); + } + break; + } + default: + { + if (this->initiator) + { + handle_attribute(this, ca); + } + } + } +} + +/** + * Scan for configuration payloads and attributes + */ +static void process_payloads(private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator, *attributes; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CONFIGURATION_V1) + { + cp_payload_t *cp = (cp_payload_t*)payload; + configuration_attribute_t *ca; + + switch (cp->get_type(cp)) + { + case CFG_REQUEST: + this->identifier = cp->get_identifier(cp); + /* FALL */ + case CFG_REPLY: + attributes = cp->create_attribute_enumerator(cp); + while (attributes->enumerate(attributes, &ca)) + { + DBG2(DBG_IKE, "processing %N attribute", + configuration_attribute_type_names, ca->get_type(ca)); + process_attribute(this, ca); + } + attributes->destroy(attributes); + break; + default: + DBG1(DBG_IKE, "ignoring %N config payload", + config_type_names, cp->get_type(cp)); + break; + } + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_mode_config_t *this, message_t *message) +{ + cp_payload_t *cp; + enumerator_t *enumerator; + attribute_handler_t *handler; + peer_cfg_t *config; + configuration_attribute_type_t type; + chunk_t data; + linked_list_t *vips; + host_t *host; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + + vips = linked_list_create(); + + /* reuse virtual IP if we already have one */ + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + + if (vips->get_count(vips) == 0) + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + enumerator = config->create_virtual_ip_enumerator(config); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + } + + if (vips->get_count(vips)) + { + enumerator = vips->create_enumerator(vips); + while (enumerator->enumerate(enumerator, &host)) + { + cp->add_attribute(cp, build_vip(host)); + } + enumerator->destroy(enumerator); + } + + enumerator = hydra->attributes->create_initiator_enumerator( + hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), vips); + while (enumerator->enumerate(enumerator, &handler, &type, &data)) + { + entry_t *entry; + + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, data)); + INIT(entry, + .type = type, + .handler = handler, + ); + this->requested->insert_last(this->requested, entry); + } + enumerator->destroy(enumerator); + + vips->destroy(vips); + + message->add_payload(message, (payload_t*)cp); + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_mode_config_t *this, message_t *message) +{ + process_payloads(this, message); + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + cp_payload_t *cp; + peer_cfg_t *config; + identification_t *id; + linked_list_t *vips, *pools; + host_t *requested; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + + id = this->ike_sa->get_other_eap_id(this->ike_sa); + config = this->ike_sa->get_peer_cfg(this->ike_sa); + vips = linked_list_create(); + pools = linked_list_create_from_enumerator( + config->create_pool_enumerator(config)); + + this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE); + + enumerator = this->vips->create_enumerator(this->vips); + while (enumerator->enumerate(enumerator, &requested)) + { + host_t *found = NULL; + + /* query all pools until we get an address */ + DBG1(DBG_IKE, "peer requested virtual IP %H", requested); + + found = hydra->attributes->acquire_address(hydra->attributes, + pools, id, requested); + if (found) + { + DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id); + this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found); + cp->add_attribute(cp, build_vip(found)); + vips->insert_last(vips, found); + } + else + { + DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'", + requested, id); + } + } + enumerator->destroy(enumerator); + + /* query registered providers for additional attributes to include */ + enumerator = hydra->attributes->create_responder_enumerator( + hydra->attributes, pools, id, vips); + while (enumerator->enumerate(enumerator, &type, &value)) + { + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, value)); + } + enumerator->destroy(enumerator); + vips->destroy_offset(vips, offsetof(host_t, destroy)); + pools->destroy(pools); + + cp->set_identifier(cp, this->identifier); + message->add_payload(message, (payload_t*)cp); + + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator; + host_t *host; + + process_payloads(this, message); + + this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE); + + enumerator = this->vips->create_enumerator(this->vips); + while (enumerator->enumerate(enumerator, &host)) + { + if (!host->is_anyaddr(host)) + { + this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host); + } + } + enumerator->destroy(enumerator); + + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_mode_config_t *this) +{ + return TASK_MODE_CONFIG; +} + +METHOD(task_t, migrate, void, + private_mode_config_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->vips = linked_list_create(); + this->requested->destroy_function(this->requested, free); + this->requested = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_mode_config_t *this) +{ + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->requested->destroy_function(this->requested, free); + free(this); +} + +/* + * Described in header. + */ +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator) +{ + private_mode_config_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .requested = linked_list_create(), + .vips = linked_list_create(), + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/mode_config.h b/src/libcharon/sa/ikev1/tasks/mode_config.h new file mode 100644 index 000000000..462bee374 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/mode_config.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mode_config mode_config + * @{ @ingroup tasks_v1 + */ + +#ifndef MODE_CONFIG_H_ +#define MODE_CONFIG_H_ + +typedef struct mode_config_t mode_config_t; + +#include +#include +#include + +/** + * Task of type TASK_MODE_COFNIG, IKEv1 configuration attribute exchange. + */ +struct mode_config_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new mode_config task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return mode_config task to handle by the task_manager + */ +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** MODE_CONFIG_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c new file mode 100644 index 000000000..db48bc58e --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "quick_delete.h" + +#include +#include + +typedef struct private_quick_delete_t private_quick_delete_t; + +/** + * Private members of a quick_delete_t task. + */ +struct private_quick_delete_t { + + /** + * Public methods and task_t interface. + */ + quick_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Protocol of CHILD_SA to delete + */ + protocol_id_t protocol; + + /** + * Inbound SPI of CHILD_SA to delete + */ + u_int32_t spi; + + /** + * Send delete even if SA does not exist + */ + bool force; + + /** + * SA already expired? + */ + bool expired; +}; + +/** + * Delete the specified CHILD_SA, if found + */ +static bool delete_child(private_quick_delete_t *this, + protocol_id_t protocol, u_int32_t spi) +{ + u_int64_t bytes_in, bytes_out; + child_sa_t *child_sa; + bool rekeyed; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); + if (!child_sa) + { /* fallback and check for outbound SA */ + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE); + if (!child_sa) + { + return FALSE; + } + this->spi = spi = child_sa->get_spi(child_sa, TRUE); + } + + rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING; + child_sa->set_state(child_sa, CHILD_DELETING); + + if (this->expired) + { + DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + else + { + child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); + child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); + + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs " + "%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, + ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + + if (!rekeyed) + { + charon->bus->child_updown(charon->bus, child_sa, FALSE); + } + + this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); + + /* TODO-IKEv1: handle close action? */ + + return TRUE; +} + +METHOD(task_t, build_i, status_t, + private_quick_delete_t *this, message_t *message) +{ + if (delete_child(this, this->protocol, this->spi) || this->force) + { + delete_payload_t *delete_payload; + + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, this->protocol, ntohl(this->spi)); + + delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP); + delete_payload->add_spi(delete_payload, this->spi); + message->add_payload(message, &delete_payload->payload_interface); + + return SUCCESS; + } + this->ike_sa->flush_queue(this->ike_sa, TASK_QUEUE_ACTIVE); + return ALREADY_DONE; +} + +METHOD(task_t, process_i, status_t, + private_quick_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_quick_delete_t *this, message_t *message) +{ + enumerator_t *payloads, *spis; + payload_t *payload; + delete_payload_t *delete_payload; + protocol_id_t protocol; + u_int32_t spi; + + payloads = message->create_payload_enumerator(message); + while (payloads->enumerate(payloads, &payload)) + { + if (payload->get_type(payload) == DELETE_V1) + { + delete_payload = (delete_payload_t*)payload; + protocol = delete_payload->get_protocol_id(delete_payload); + if (protocol != PROTO_ESP && protocol != PROTO_AH) + { + continue; + } + spis = delete_payload->create_spi_enumerator(delete_payload); + while (spis->enumerate(spis, &spi)) + { + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); + if (!delete_child(this, protocol, spi)) + { + DBG1(DBG_IKE, "CHILD_SA not found, ignored"); + continue; + } + } + spis->destroy(spis); + } + } + payloads->destroy(payloads); + + return SUCCESS; +} + +METHOD(task_t, build_r, status_t, + private_quick_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_quick_delete_t *this) +{ + return TASK_QUICK_DELETE; +} + +METHOD(task_t, migrate, void, + private_quick_delete_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_quick_delete_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi, bool force, bool expired) +{ + private_quick_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .protocol = protocol, + .spi = spi, + .force = force, + .expired = expired, + ); + + if (protocol != PROTO_NONE) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.h b/src/libcharon/sa/ikev1/tasks/quick_delete.h new file mode 100644 index 000000000..4df30c8fe --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup quick_delete quick_delete + * @{ @ingroup tasks_v1 + */ + +#ifndef QUICK_DELETE_H_ +#define QUICK_DELETE_H_ + +typedef struct quick_delete_t quick_delete_t; + +#include +#include +#include +#include + +/** + * Task of type QUICK_DELETE, delete an IKEv1 quick mode SA. + */ +struct quick_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new quick_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder + * @param spi inbound SPI of CHILD_SA to delete + * @param force send delete even if SA does not exist + * @param expired TRUE if SA already expired + * @return quick_delete task to handle by the task_manager + */ +quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi, bool force, bool expired); + +#endif /** QUICK_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c new file mode 100644 index 000000000..82a7238c3 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -0,0 +1,1273 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "quick_mode.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_quick_mode_t private_quick_mode_t; + +/** + * Private members of a quick_mode_t task. + */ +struct private_quick_mode_t { + + /** + * Public methods and task_t interface. + */ + quick_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * TRUE if we are initiating quick mode + */ + bool initiator; + + /** + * Traffic selector of initiator + */ + traffic_selector_t *tsi; + + /** + * Traffic selector of responder + */ + traffic_selector_t *tsr; + + /** + * Initiators nonce + */ + chunk_t nonce_i; + + /** + * Responder nonce + */ + chunk_t nonce_r; + + /** + * Initiators ESP SPI + */ + u_int32_t spi_i; + + /** + * Responder ESP SPI + */ + u_int32_t spi_r; + + /** + * Initiators IPComp CPI + */ + u_int16_t cpi_i; + + /** + * Responders IPComp CPI + */ + u_int16_t cpi_r; + + /** + * selected CHILD_SA proposal + */ + proposal_t *proposal; + + /** + * Config of CHILD_SA to establish + */ + child_cfg_t *config; + + /** + * CHILD_SA we are about to establish + */ + child_sa_t *child_sa; + + /** + * IKEv1 keymat + */ + keymat_v1_t *keymat; + + /** + * DH exchange, when PFS is in use + */ + diffie_hellman_t *dh; + + /** + * Negotiated lifetime of new SA + */ + u_int32_t lifetime; + + /** + * Negotaited lifebytes of new SA + */ + u_int64_t lifebytes; + + /** + * Reqid to use, 0 for auto-allocate + */ + u_int32_t reqid; + + /** + * SPI of SA we rekey + */ + u_int32_t rekey; + + /** + * Negotiated mode, tunnel or transport + */ + ipsec_mode_t mode; + + /** + * Use UDP encapsulation + */ + bool udp; + + /** states of quick mode */ + enum { + QM_INIT, + QM_NEGOTIATED, + } state; +}; + +/** + * Schedule inactivity timeout for CHILD_SA with reqid, if enabled + */ +static void schedule_inactivity_timeout(private_quick_mode_t *this) +{ + u_int32_t timeout; + bool close_ike; + + timeout = this->config->get_inactivity(this->config); + if (timeout) + { + close_ike = lib->settings->get_bool(lib->settings, + "%s.inactivity_close_ike", FALSE, charon->name); + lib->scheduler->schedule_job(lib->scheduler, (job_t*) + inactivity_job_create(this->child_sa->get_reqid(this->child_sa), + timeout, close_ike), timeout); + } +} + +/** + * Check if we have a an address pool configured + */ +static bool have_pool(ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + char *pool; + bool found = FALSE; + + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_pool_enumerator(peer_cfg); + if (enumerator->enumerate(enumerator, &pool)) + { + found = TRUE; + } + enumerator->destroy(enumerator); + } + return found; +} + +/** + * Get hosts to use for dynamic traffic selectors + */ +static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local) +{ + enumerator_t *enumerator; + linked_list_t *list; + host_t *host; + + list = linked_list_create(); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local); + while (enumerator->enumerate(enumerator, &host)) + { + list->insert_last(list, host); + } + enumerator->destroy(enumerator); + + if (list->get_count(list) == 0) + { /* no virtual IPs assigned */ + if (local) + { + host = ike_sa->get_my_host(ike_sa); + list->insert_last(list, host); + } + else if (!have_pool(ike_sa)) + { /* use host only if we don't have a pool configured */ + host = ike_sa->get_other_host(ike_sa); + list->insert_last(list, host); + } + } + return list; +} + +/** + * Install negotiated CHILD_SA + */ +static bool install(private_quick_mode_t *this) +{ + status_t status, status_i, status_o; + chunk_t encr_i, encr_r, integ_i, integ_r; + linked_list_t *tsi, *tsr; + child_sa_t *old = NULL; + + this->child_sa->set_proposal(this->child_sa, this->proposal); + this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); + this->child_sa->set_mode(this->child_sa, this->mode); + + if (this->cpi_i && this->cpi_r) + { /* DEFLATE is the only transform we currently support */ + this->child_sa->set_ipcomp(this->child_sa, IPCOMP_DEFLATE); + } + else + { + this->cpi_i = this->cpi_r = 0; + } + + this->child_sa->set_protocol(this->child_sa, + this->proposal->get_protocol(this->proposal)); + + status_i = status_o = FAILED; + encr_i = encr_r = integ_i = integ_r = chunk_empty; + tsi = linked_list_create_with_items(this->tsi->clone(this->tsi), NULL); + tsr = linked_list_create_with_items(this->tsr->clone(this->tsr), NULL); + if (this->initiator) + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_POST_AUTH, tsi, tsr); + } + else + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER_POST, tsr, tsi); + } + if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0) + { + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + DBG1(DBG_IKE, "no acceptable traffic selectors found"); + return FALSE; + } + + if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh, + this->spi_i, this->spi_r, this->nonce_i, this->nonce_r, + &encr_i, &integ_i, &encr_r, &integ_r)) + { + if (this->initiator) + { + status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->spi_i, this->cpi_i, TRUE, FALSE, tsi, tsr); + status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->spi_r, this->cpi_r, FALSE, FALSE, tsi, tsr); + } + else + { + status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->spi_r, this->cpi_r, TRUE, FALSE, tsr, tsi); + status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->spi_i, this->cpi_i, FALSE, FALSE, tsr, tsi); + } + } + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); + + if (status_i != SUCCESS || status_o != SUCCESS) + { + DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel", + (status_i != SUCCESS) ? "inbound " : "", + (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", + (status_o != SUCCESS) ? "outbound " : ""); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + return FALSE; + } + + if (this->initiator) + { + status = this->child_sa->add_policies(this->child_sa, tsi, tsr); + } + else + { + status = this->child_sa->add_policies(this->child_sa, tsr, tsi); + } + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); + return FALSE; + } + + charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, + this->dh, this->nonce_i, this->nonce_r); + + /* add to IKE_SA, and remove from task */ + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + + if (this->rekey) + { + old = this->ike_sa->get_child_sa(this->ike_sa, + this->proposal->get_protocol(this->proposal), + this->rekey, TRUE); + } + if (old) + { + charon->bus->child_rekey(charon->bus, old, this->child_sa); + } + else + { + charon->bus->child_updown(charon->bus, this->child_sa, TRUE); + } + if (!this->rekey) + { + schedule_inactivity_timeout(this); + } + this->child_sa = NULL; + return TRUE; +} + +/** + * Generate and add NONCE + */ +static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + nonce_gen_t *nonceg; + + nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); + if (!nonceg) + { + DBG1(DBG_IKE, "no nonce generator found to create nonce"); + return FALSE; + } + if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, nonce)) + { + DBG1(DBG_IKE, "nonce allocation failed"); + nonceg->destroy(nonceg); + return FALSE; + } + nonceg->destroy(nonceg); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, *nonce); + message->add_payload(message, &nonce_payload->payload_interface); + + return TRUE; +} + +/** + * Extract nonce from NONCE payload + */ +static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "NONCE payload missing in message"); + return FALSE; + } + *nonce = nonce_payload->get_nonce(nonce_payload); + + return TRUE; +} + +/** + * Add KE payload to message + */ +static void add_ke(private_quick_mode_t *this, message_t *message) +{ + ke_payload_t *ke_payload; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh); + message->add_payload(message, &ke_payload->payload_interface); +} + +/** + * Get DH value from a KE payload + */ +static bool get_ke(private_quick_mode_t *this, message_t *message) +{ + ke_payload_t *ke_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing"); + return FALSE; + } + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + return TRUE; +} + +/** + * Select a traffic selector from configuration + */ +static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local, + linked_list_t *supplied) +{ + traffic_selector_t *ts; + linked_list_t *list, *hosts; + + hosts = get_dynamic_hosts(this->ike_sa, local); + list = this->config->get_traffic_selectors(this->config, + local, supplied, hosts); + hosts->destroy(hosts); + if (list->get_first(list, (void**)&ts) == SUCCESS) + { + ts = ts->clone(ts); + } + else + { + DBG1(DBG_IKE, "%s traffic selector missing in configuration", + local ? "local" : "local"); + ts = NULL; + } + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + return ts; +} + +/** + * Add selected traffic selectors to message + */ +static void add_ts(private_quick_mode_t *this, message_t *message) +{ + id_payload_t *id_payload; + host_t *hsi, *hsr; + + if (this->initiator) + { + hsi = this->ike_sa->get_my_host(this->ike_sa); + hsr = this->ike_sa->get_other_host(this->ike_sa); + } + else + { + hsr = this->ike_sa->get_my_host(this->ike_sa); + hsi = this->ike_sa->get_other_host(this->ike_sa); + } + /* add ID payload only if negotiating non host2host tunnels */ + if (!this->tsi->is_host(this->tsi, hsi) || + !this->tsr->is_host(this->tsr, hsr) || + this->tsi->get_protocol(this->tsi) || + this->tsr->get_protocol(this->tsr) || + this->tsi->get_from_port(this->tsi) || + this->tsr->get_from_port(this->tsr) || + this->tsi->get_to_port(this->tsi) != 65535 || + this->tsr->get_to_port(this->tsr) != 65535) + { + id_payload = id_payload_create_from_ts(this->tsi); + message->add_payload(message, &id_payload->payload_interface); + id_payload = id_payload_create_from_ts(this->tsr); + message->add_payload(message, &id_payload->payload_interface); + } +} + +/** + * Get traffic selectors from received message + */ +static bool get_ts(private_quick_mode_t *this, message_t *message) +{ + traffic_selector_t *tsi = NULL, *tsr = NULL; + enumerator_t *enumerator; + id_payload_t *id_payload; + payload_t *payload; + host_t *hsi, *hsr; + bool first = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == ID_V1) + { + id_payload = (id_payload_t*)payload; + + if (first) + { + tsi = id_payload->get_ts(id_payload); + first = FALSE; + } + else + { + tsr = id_payload->get_ts(id_payload); + break; + } + } + } + enumerator->destroy(enumerator); + + /* create host2host selectors if ID payloads missing */ + if (this->initiator) + { + hsi = this->ike_sa->get_my_host(this->ike_sa); + hsr = this->ike_sa->get_other_host(this->ike_sa); + } + else + { + hsr = this->ike_sa->get_my_host(this->ike_sa); + hsi = this->ike_sa->get_other_host(this->ike_sa); + } + if (!tsi) + { + tsi = traffic_selector_create_from_subnet(hsi->clone(hsi), + hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0); + } + if (!tsr) + { + tsr = traffic_selector_create_from_subnet(hsr->clone(hsr), + hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0); + } + if (!this->initiator && this->mode == MODE_TRANSPORT && this->udp && + (!tsi->is_host(tsi, hsi) || !tsr->is_host(tsr, hsr))) + { /* change TS in case of a NAT in transport mode */ + DBG2(DBG_IKE, "changing received traffic selectors %R=== %R due to NAT", + tsi, tsr); + tsi->set_address(tsi, hsi); + tsr->set_address(tsr, hsr); + } + + if (this->initiator) + { + /* check if peer selection valid */ + if (!tsr->is_contained_in(tsr, this->tsr) || + !tsi->is_contained_in(tsi, this->tsi)) + { + DBG1(DBG_IKE, "peer selected invalid traffic selectors: ", + "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr); + tsi->destroy(tsi); + tsr->destroy(tsr); + return FALSE; + } + this->tsi->destroy(this->tsi); + this->tsr->destroy(this->tsr); + this->tsi = tsi; + this->tsr = tsr; + } + else + { + this->tsi = tsi; + this->tsr = tsr; + } + return TRUE; +} + +/** + * Add NAT-OA payloads + */ +static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message) +{ + identification_t *id; + id_payload_t *nat_oa; + host_t *src, *dst; + + src = message->get_source(message); + dst = message->get_destination(message); + + src = this->initiator ? src : dst; + dst = this->initiator ? dst : src; + + /* first NAT-OA is the initiator's address */ + id = identification_create_from_sockaddr(src->get_sockaddr(src)); + nat_oa = id_payload_create_from_identification(NAT_OA_V1, id); + message->add_payload(message, (payload_t*)nat_oa); + id->destroy(id); + + /* second NAT-OA is that of the responder */ + id = identification_create_from_sockaddr(dst->get_sockaddr(dst)); + nat_oa = id_payload_create_from_identification(NAT_OA_V1, id); + message->add_payload(message, (payload_t*)nat_oa); + id->destroy(id); +} + +/** + * Look up lifetimes + */ +static void get_lifetimes(private_quick_mode_t *this) +{ + lifetime_cfg_t *lft; + + lft = this->config->get_lifetime(this->config); + if (lft->time.life) + { + this->lifetime = lft->time.life; + } + else if (lft->bytes.life) + { + this->lifebytes = lft->bytes.life; + } + free(lft); +} + +/** + * Check and apply lifetimes + */ +static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload) +{ + u_int32_t lifetime; + u_int64_t lifebytes; + + lifetime = sa_payload->get_lifetime(sa_payload); + lifebytes = sa_payload->get_lifebytes(sa_payload); + if (this->lifetime != lifetime) + { + DBG1(DBG_IKE, "received %us lifetime, configured %us", + lifetime, this->lifetime); + this->lifetime = lifetime; + } + if (this->lifebytes != lifebytes) + { + DBG1(DBG_IKE, "received %llu lifebytes, configured %llu", + lifebytes, this->lifebytes); + this->lifebytes = lifebytes; + } +} + +/** + * Set the task ready to build notify error message + */ +static status_t send_notify(private_quick_mode_t *this, notify_type_t type) +{ + notify_payload_t *notify; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_ESP, type); + notify->set_spi(notify, this->spi_i); + + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + this->ike_sa->flush_queue(this->ike_sa, + this->initiator ? TASK_QUEUE_ACTIVE : TASK_QUEUE_PASSIVE); + return ALREADY_DONE; +} + +METHOD(task_t, build_i, status_t, + private_quick_mode_t *this, message_t *message) +{ + switch (this->state) + { + case QM_INIT: + { + enumerator_t *enumerator; + sa_payload_t *sa_payload; + linked_list_t *list, *tsi, *tsr; + proposal_t *proposal; + diffie_hellman_group_t group; + + this->udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); + this->mode = this->config->get_mode(this->config); + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->config, this->reqid, this->udp); + + if (this->udp && this->mode == MODE_TRANSPORT) + { + /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ + add_nat_oa_payloads(this, message); + } + + if (this->config->use_ipcomp(this->config)) + { + if (this->udp) + { + DBG1(DBG_IKE, "IPComp is not supported if either peer is " + "natted, IPComp disabled"); + } + else + { + this->cpi_i = this->child_sa->alloc_cpi(this->child_sa); + if (!this->cpi_i) + { + DBG1(DBG_IKE, "unable to allocate a CPI from kernel, " + "IPComp disabled"); + } + } + } + + this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (!this->spi_i) + { + DBG1(DBG_IKE, "allocating SPI from kernel failed"); + return FAILED; + } + + list = this->config->get_proposals(this->config, FALSE); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &proposal)) + { + proposal->set_spi(proposal, this->spi_i); + } + enumerator->destroy(enumerator); + + get_lifetimes(this); + sa_payload = sa_payload_create_from_proposals_v1(list, + this->lifetime, this->lifebytes, AUTH_NONE, + this->mode, this->udp, this->cpi_i); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + message->add_payload(message, &sa_payload->payload_interface); + + if (!add_nonce(this, &this->nonce_i, message)) + { + return FAILED; + } + + group = this->config->get_dh_group(this->config); + if (group != MODP_NONE) + { + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + group); + if (!this->dh) + { + DBG1(DBG_IKE, "configured DH group %N not supported", + diffie_hellman_group_names, group); + return FAILED; + } + add_ke(this, message); + } + if (!this->tsi) + { + this->tsi = select_ts(this, TRUE, NULL); + } + if (!this->tsr) + { + this->tsr = select_ts(this, FALSE, NULL); + } + tsi = linked_list_create_with_items(this->tsi, NULL); + tsr = linked_list_create_with_items(this->tsr, NULL); + this->tsi = this->tsr = NULL; + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_PRE_AUTH, tsi, tsr); + tsi->remove_first(tsi, (void**)&this->tsi); + tsr->remove_first(tsr, (void**)&this->tsr); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + if (!this->tsi || !this->tsr) + { + return FAILED; + } + add_ts(this, message); + return NEED_MORE; + } + case QM_NEGOTIATED: + { + return SUCCESS; + } + default: + return FAILED; + } +} + +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_quick_mode_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } + } + enumerator->destroy(enumerator); + + return err; +} + +/** + * Check if this is a rekey for an existing CHILD_SA, reuse reqid if so + */ +static void check_for_rekeyed_child(private_quick_mode_t *this) +{ + enumerator_t *enumerator, *policies; + traffic_selector_t *local, *remote; + child_sa_t *child_sa; + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (this->reqid == 0 && enumerator->enumerate(enumerator, &child_sa)) + { + if (child_sa->get_state(child_sa) == CHILD_INSTALLED && + streq(child_sa->get_name(child_sa), + this->config->get_name(this->config))) + { + policies = child_sa->create_policy_enumerator(child_sa); + if (policies->enumerate(policies, &local, &remote)) + { + if (local->equals(local, this->tsr) && + remote->equals(remote, this->tsi) && + this->proposal->equals(this->proposal, + child_sa->get_proposal(child_sa))) + { + this->reqid = child_sa->get_reqid(child_sa); + this->rekey = child_sa->get_spi(child_sa, TRUE); + child_sa->set_state(child_sa, CHILD_REKEYING); + DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}", + child_sa->get_name(child_sa), this->reqid); + } + } + policies->destroy(policies); + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, process_r, status_t, + private_quick_mode_t *this, message_t *message) +{ + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + linked_list_t *tsi, *tsr, *hostsi, *hostsr, *list = NULL; + peer_cfg_t *peer_cfg; + u_int16_t group; + bool private; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "sa payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + this->mode = sa_payload->get_encap_mode(sa_payload, &this->udp); + + if (!get_ts(this, message)) + { + return FAILED; + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + tsi = linked_list_create_with_items(this->tsi, NULL); + tsr = linked_list_create_with_items(this->tsr, NULL); + this->tsi = this->tsr = NULL; + hostsi = get_dynamic_hosts(this->ike_sa, FALSE); + hostsr = get_dynamic_hosts(this->ike_sa, TRUE); + this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi, + hostsr, hostsi); + hostsi->destroy(hostsi); + hostsr->destroy(hostsr); + if (this->config) + { + this->tsi = select_ts(this, FALSE, tsi); + this->tsr = select_ts(this, TRUE, tsr); + } + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + if (!this->config || !this->tsi || !this->tsr) + { + DBG1(DBG_IKE, "no matching CHILD_SA config found"); + return send_notify(this, INVALID_ID_INFORMATION); + } + + if (this->config->use_ipcomp(this->config)) + { + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + DBG1(DBG_IKE, "IPComp is not supported if either peer is " + "natted, IPComp disabled"); + } + else + { + list = sa_payload->get_ipcomp_proposals(sa_payload, + &this->cpi_i); + if (!list->get_count(list)) + { + DBG1(DBG_IKE, "expected IPComp proposal but peer did " + "not send one, IPComp disabled"); + this->cpi_i = 0; + } + } + } + if (!list || !list->get_count(list)) + { + DESTROY_IF(list); + list = sa_payload->get_proposals(sa_payload); + } + private = this->ike_sa->supports_extension(this->ike_sa, + EXT_STRONGSWAN); + this->proposal = this->config->select_proposal(this->config, + list, FALSE, private); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + + get_lifetimes(this); + apply_lifetimes(this, sa_payload); + + if (!this->proposal) + { + DBG1(DBG_IKE, "no matching proposal found, sending %N", + notify_type_names, NO_PROPOSAL_CHOSEN); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->spi_i = this->proposal->get_spi(this->proposal); + + if (!get_nonce(this, &this->nonce_i, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + if (this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + group); + if (!this->dh) + { + DBG1(DBG_IKE, "negotiated DH group %N not supported", + diffie_hellman_group_names, group); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!get_ke(this, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + } + + check_for_rekeyed_child(this); + + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->config, this->reqid, this->udp); + + tsi = linked_list_create_with_items(this->tsi, NULL); + tsr = linked_list_create_with_items(this->tsr, NULL); + this->tsi = this->tsr = NULL; + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER, tsr, tsi); + if (tsi->remove_first(tsi, (void**)&this->tsi) != SUCCESS || + tsr->remove_first(tsr, (void**)&this->tsr) != SUCCESS) + { + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + return send_notify(this, INVALID_ID_INFORMATION); + } + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + + return NEED_MORE; + } + case QM_NEGOTIATED: + { + if (message->get_exchange_type(message) == INFORMATIONAL_V1 || + has_notify_errors(this, message)) + { + return SUCCESS; + } + if (!install(this)) + { + ike_sa_t *ike_sa = this->ike_sa; + task_t *task; + + task = (task_t*)quick_delete_create(this->ike_sa, + this->proposal->get_protocol(this->proposal), + this->spi_i, TRUE, TRUE); + /* flush_queue() destroys the current task */ + ike_sa->flush_queue(ike_sa, TASK_QUEUE_PASSIVE); + ike_sa->queue_task(ike_sa, task); + return ALREADY_DONE; + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_quick_mode_t *this, message_t *message) +{ + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + + this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (!this->spi_r) + { + DBG1(DBG_IKE, "allocating SPI from kernel failed"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->proposal->set_spi(this->proposal, this->spi_r); + + if (this->cpi_i) + { + this->cpi_r = this->child_sa->alloc_cpi(this->child_sa); + if (!this->cpi_r) + { + DBG1(DBG_IKE, "unable to allocate a CPI from " + "kernel, IPComp disabled"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + } + + if (this->udp && this->mode == MODE_TRANSPORT) + { + /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ + add_nat_oa_payloads(this, message); + } + + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + this->lifetime, this->lifebytes, AUTH_NONE, + this->mode, this->udp, this->cpi_r); + message->add_payload(message, &sa_payload->payload_interface); + + if (!add_nonce(this, &this->nonce_r, message)) + { + return FAILED; + } + if (this->dh) + { + add_ke(this, message); + } + + add_ts(this, message); + + this->state = QM_NEGOTIATED; + return NEED_MORE; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_quick_mode_t *this, message_t *message) +{ + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + linked_list_t *list = NULL; + bool private; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "sa payload missing"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (this->cpi_i) + { + list = sa_payload->get_ipcomp_proposals(sa_payload, + &this->cpi_r); + if (!list->get_count(list)) + { + DBG1(DBG_IKE, "peer did not acccept our IPComp proposal, " + "IPComp disabled"); + this->cpi_i = 0; + } + } + if (!list || !list->get_count(list)) + { + DESTROY_IF(list); + list = sa_payload->get_proposals(sa_payload); + } + private = this->ike_sa->supports_extension(this->ike_sa, + EXT_STRONGSWAN); + this->proposal = this->config->select_proposal(this->config, + list, FALSE, private); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no matching proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->spi_r = this->proposal->get_spi(this->proposal); + + apply_lifetimes(this, sa_payload); + + if (!get_nonce(this, &this->nonce_r, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (this->dh && !get_ke(this, message)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!get_ts(this, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!install(this)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + this->state = QM_NEGOTIATED; + return NEED_MORE; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_quick_mode_t *this) +{ + return TASK_QUICK_MODE; +} + +METHOD(quick_mode_t, use_reqid, void, + private_quick_mode_t *this, u_int32_t reqid) +{ + this->reqid = reqid; +} + +METHOD(quick_mode_t, rekey, void, + private_quick_mode_t *this, u_int32_t spi) +{ + this->rekey = spi; +} + +METHOD(task_t, migrate, void, + private_quick_mode_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->nonce_i); + chunk_free(&this->nonce_r); + DESTROY_IF(this->tsi); + DESTROY_IF(this->tsr); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->dh); + + this->ike_sa = ike_sa; + this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + this->state = QM_INIT; + this->tsi = NULL; + this->tsr = NULL; + this->proposal = NULL; + this->child_sa = NULL; + this->dh = NULL; + this->spi_i = 0; + this->spi_r = 0; + + if (!this->initiator) + { + DESTROY_IF(this->config); + this->config = NULL; + } +} + +METHOD(task_t, destroy, void, + private_quick_mode_t *this) +{ + chunk_free(&this->nonce_i); + chunk_free(&this->nonce_r); + DESTROY_IF(this->tsi); + DESTROY_IF(this->tsr); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->config); + DESTROY_IF(this->dh); + free(this); +} + +/* + * Described in header. + */ +quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + private_quick_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .use_reqid = _use_reqid, + .rekey = _rekey, + }, + .ike_sa = ike_sa, + .initiator = config != NULL, + .config = config, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + .state = QM_INIT, + .tsi = tsi ? tsi->clone(tsi) : NULL, + .tsr = tsr ? tsr->clone(tsr) : NULL, + ); + + if (config) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h new file mode 100644 index 000000000..0b80cb836 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup quick_mode quick_mode + * @{ @ingroup tasks_v1 + */ + +#ifndef QUICK_MODE_H_ +#define QUICK_MODE_H_ + +typedef struct quick_mode_t quick_mode_t; + +#include +#include +#include + +/** + * IKEv1 quick mode, establishes a CHILD_SA in IKEv1. + */ +struct quick_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Use a specific reqid to install this CHILD_SA. + * + * @param reqid reqid to use + */ + void (*use_reqid)(quick_mode_t *this, u_int32_t reqid); + + /** + * Set the SPI of the old SA, if rekeying. + * + * @param spi spi of SA to rekey + */ + void (*rekey)(quick_mode_t *this, u_int32_t spi); +}; + +/** + * Create a new quick_mode task. + * + * @param ike_sa IKE_SA this task works for + * @param config child_cfg if task initiator, NULL if responder + * @param tsi source of triggering packet, or NULL + * @param tsr destination of triggering packet, or NULL + * @return task to handle by the task_manager + */ +quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr); + +#endif /** QUICK_MODE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c new file mode 100644 index 000000000..10bea5636 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -0,0 +1,551 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth.h" + +#include +#include +#include +#include + +typedef struct private_xauth_t private_xauth_t; + +/** + * Status types exchanged + */ +typedef enum { + XAUTH_FAILED = 0, + XAUTH_OK = 1, +} xauth_status_t; + +/** + * Private members of a xauth_t task. + */ +struct private_xauth_t { + + /** + * Public methods and task_t interface. + */ + xauth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the XAUTH initiator? + */ + bool initiator; + + /** + * XAuth backend to use + */ + xauth_method_t *xauth; + + /** + * XAuth username + */ + identification_t *user; + + /** + * Generated configuration payload + */ + cp_payload_t *cp; + + /** + * received identifier + */ + u_int16_t identifier; + + /** + * status of Xauth exchange + */ + xauth_status_t status; +}; + +/** + * Load XAuth backend + */ +static xauth_method_t *load_method(private_xauth_t* this) +{ + identification_t *server, *peer; + enumerator_t *enumerator; + xauth_method_t *xauth; + xauth_role_t role; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth; + char *name; + + if (this->initiator) + { + server = this->ike_sa->get_my_id(this->ike_sa); + peer = this->ike_sa->get_other_id(this->ike_sa); + role = XAUTH_SERVER; + } + else + { + peer = this->ike_sa->get_my_id(this->ike_sa); + server = this->ike_sa->get_other_id(this->ike_sa); + role = XAUTH_PEER; + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator); + if (!enumerator->enumerate(enumerator, &auth) || + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH) + { + if (!enumerator->enumerate(enumerator, &auth) || + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH) + { + DBG1(DBG_CFG, "no XAuth authentication round found"); + enumerator->destroy(enumerator); + return NULL; + } + } + name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND); + this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY); + enumerator->destroy(enumerator); + if (!this->initiator && this->user) + { /* use XAUTH username, if configured */ + peer = this->user; + } + xauth = charon->xauth->create_instance(charon->xauth, name, role, + server, peer); + if (!xauth) + { + if (name) + { + DBG1(DBG_CFG, "no XAuth method found named '%s'", name); + } + else + { + DBG1(DBG_CFG, "no XAuth method found"); + } + } + return xauth; +} + +/** + * Check if XAuth connection is allowed to succeed + */ +static bool allowed(private_xauth_t *this) +{ + if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling XAuth due to uniqueness policy"); + return FALSE; + } + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + return TRUE; +} + +/** + * Set IKE_SA to established state + */ +static bool establish(private_xauth_t *this) +{ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; +} + +/** + * Check if we are compliant to a given peer config + */ +static bool is_compliant(private_xauth_t *this, peer_cfg_t *peer_cfg, bool log) +{ + bool complies = TRUE; + enumerator_t *e1, *e2; + auth_cfg_t *c1, *c2; + + e1 = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE); + while (e1->enumerate(e1, &c1)) + { + if (!e2->enumerate(e2, &c2) || !c2->complies(c2, c1, log)) + { + complies = FALSE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + + return complies; +} + +/** + * Check if we are compliant to current config, switch to another if not + */ +static bool select_compliant_config(private_xauth_t *this) +{ + peer_cfg_t *peer_cfg = NULL, *old, *current; + identification_t *my_id, *other_id; + host_t *my_host, *other_host; + enumerator_t *enumerator; + bool aggressive; + + old = this->ike_sa->get_peer_cfg(this->ike_sa); + if (is_compliant(this, old, TRUE)) + { /* current config is fine */ + return TRUE; + } + DBG1(DBG_CFG, "selected peer config '%s' inacceptable", + old->get_name(old)); + aggressive = old->use_aggressive(old); + + my_host = this->ike_sa->get_my_host(this->ike_sa); + other_host = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + my_host, other_host, my_id, other_id, IKEV1); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (!current->equals(current, old) && + current->use_aggressive(current) == aggressive && + is_compliant(this, current, FALSE)) + { + peer_cfg = current; + break; + } + } + if (peer_cfg) + { + DBG1(DBG_CFG, "switching to peer config '%s'", + peer_cfg->get_name(peer_cfg)); + this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg); + } + else + { + DBG1(DBG_CFG, "no alternative config found"); + } + enumerator->destroy(enumerator); + + return peer_cfg != NULL; +} + +/** + * Create auth config after successful authentication + */ +static bool add_auth_cfg(private_xauth_t *this, identification_t *id, bool local) +{ + auth_cfg_t *auth; + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); + auth->add(auth, AUTH_RULE_XAUTH_IDENTITY, id->clone(id)); + auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), FALSE); + this->ike_sa->add_auth_cfg(this->ike_sa, local, auth); + + return select_compliant_config(this); +} + +METHOD(task_t, build_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + cp->add_attribute(cp, + configuration_attribute_create_value(XAUTH_STATUS, this->status)); + + message->add_payload(message, (payload_t *)cp); + + return NEED_MORE; +} + +METHOD(task_t, build_i, status_t, + private_xauth_t *this, message_t *message) +{ + if (!this->xauth) + { + cp_payload_t *cp; + + this->xauth = load_method(this); + if (!this->xauth) + { + return FAILED; + } + if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE) + { + return FAILED; + } + message->add_payload(message, (payload_t *)cp); + return NEED_MORE; + } + + if (this->cp) + { /* send previously generated payload */ + message->add_payload(message, (payload_t *)this->cp); + this->cp = NULL; + return NEED_MORE; + } + return FAILED; +} + +METHOD(task_t, build_r_ack, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK); + cp->set_identifier(cp, this->identifier); + cp->add_attribute(cp, + configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty)); + + message->add_payload(message, (payload_t *)cp); + + if (this->status == XAUTH_OK && allowed(this) && establish(this)) + { + return SUCCESS; + } + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + if (!this->xauth) + { + this->xauth = load_method(this); + if (!this->xauth) + { /* send empty reply */ + return NEED_MORE; + } + } + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp) + { + DBG1(DBG_IKE, "configuration payload missing in XAuth request"); + return FAILED; + } + if (cp->get_type(cp) == CFG_REQUEST) + { + switch (this->xauth->process(this->xauth, cp, &this->cp)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + case FAILED: + default: + break; + } + this->cp = NULL; + return NEED_MORE; + } + if (cp->get_type(cp) == CFG_SET) + { + configuration_attribute_t *attribute; + enumerator_t *enumerator; + + enumerator = cp->create_attribute_enumerator(cp); + while (enumerator->enumerate(enumerator, &attribute)) + { + if (attribute->get_type(attribute) == XAUTH_STATUS) + { + this->status = attribute->get_value(attribute); + } + } + enumerator->destroy(enumerator); + if (this->status == XAUTH_OK && + add_auth_cfg(this, this->xauth->get_identity(this->xauth), TRUE)) + { + DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful", + this->xauth->get_identity(this->xauth)); + } + else + { + DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed", + this->xauth->get_identity(this->xauth)); + } + } + this->identifier = cp->get_identifier(cp); + this->public.task.build = _build_r_ack; + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_xauth_t *this, message_t *message) +{ + if (!this->cp) + { /* send empty reply if building data failed */ + this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + } + message->add_payload(message, (payload_t *)this->cp); + this->cp = NULL; + return NEED_MORE; +} + +METHOD(task_t, process_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp || cp->get_type(cp) != CFG_ACK) + { + DBG1(DBG_IKE, "received invalid XAUTH status response"); + return FAILED; + } + if (this->status != XAUTH_OK) + { + DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication"); + return FAILED; + } + if (!establish(this)) + { + return FAILED; + } + this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE); + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create(this->ike_sa->get_id(this->ike_sa))); + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_xauth_t *this, message_t *message) +{ + identification_t *id; + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp) + { + DBG1(DBG_IKE, "configuration payload missing in XAuth response"); + return FAILED; + } + switch (this->xauth->process(this->xauth, cp, &this->cp)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + id = this->xauth->get_identity(this->xauth); + if (this->user && !id->matches(id, this->user)) + { + DBG1(DBG_IKE, "XAuth username '%Y' does not match to " + "configured username '%Y'", id, this->user); + break; + } + DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id); + if (add_auth_cfg(this, id, FALSE) && allowed(this)) + { + this->status = XAUTH_OK; + } + break; + case FAILED: + DBG1(DBG_IKE, "XAuth authentication of '%Y' failed", + this->xauth->get_identity(this->xauth)); + break; + default: + return FAILED; + } + this->public.task.build = _build_i_status; + this->public.task.process = _process_i_status; + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_xauth_t *this) +{ + return TASK_XAUTH; +} + +METHOD(task_t, migrate, void, + private_xauth_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->xauth); + DESTROY_IF(this->cp); + + this->ike_sa = ike_sa; + this->xauth = NULL; + this->cp = NULL; + this->user = NULL; + this->status = XAUTH_FAILED; + + if (this->initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } +} + +METHOD(task_t, destroy, void, + private_xauth_t *this) +{ + DESTROY_IF(this->xauth); + DESTROY_IF(this->cp); + free(this); +} + +/* + * Described in header. + */ +xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator) +{ + private_xauth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .status = XAUTH_FAILED, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/xauth.h b/src/libcharon/sa/ikev1/tasks/xauth.h new file mode 100644 index 000000000..303eb31ce --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/xauth.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_t xauth + * @{ @ingroup tasks_v1 + */ + +#ifndef XAUTH_H_ +#define XAUTH_H_ + +typedef struct xauth_t xauth_t; + +#include +#include +#include + +/** + * Task of type TASK_XAUTH, additional authentication after main/aggressive mode. + */ +struct xauth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new xauth task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return xauth task to handle by the task_manager + */ +xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** XAUTH_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c new file mode 100644 index 000000000..aa0644033 --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -0,0 +1,743 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "eap_authenticator.h" + +#include +#include +#include +#include +#include + +typedef struct private_eap_authenticator_t private_eap_authenticator_t; + +/** + * Private data of an eap_authenticator_t object. + */ +struct private_eap_authenticator_t { + + /** + * Public authenticator_t interface. + */ + eap_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * others nonce to include in AUTH calculation + */ + chunk_t received_nonce; + + /** + * our nonce to include in AUTH calculation + */ + chunk_t sent_nonce; + + /** + * others IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t received_init; + + /** + * our IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t sent_init; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; + + /** + * Current EAP method processing + */ + eap_method_t *method; + + /** + * MSK used to build and verify auth payload + */ + chunk_t msk; + + /** + * EAP authentication method completed successfully + */ + bool eap_complete; + + /** + * Set if we require mutual EAP due EAP-only authentication + */ + bool require_mutual; + + /** + * authentication payload verified successfully + */ + bool auth_complete; + + /** + * generated EAP payload + */ + eap_payload_t *eap_payload; + + /** + * EAP identity of peer + */ + identification_t *eap_identity; +}; + +/** + * load an EAP method + */ +static eap_method_t *load_method(private_eap_authenticator_t *this, + eap_type_t type, u_int32_t vendor, eap_role_t role) +{ + identification_t *server, *peer, *aaa; + auth_cfg_t *auth; + + if (role == EAP_SERVER) + { + server = this->ike_sa->get_my_id(this->ike_sa); + peer = this->ike_sa->get_other_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + } + else + { + server = this->ike_sa->get_other_id(this->ike_sa); + peer = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + } + if (this->eap_identity) + { + peer = this->eap_identity; + } + aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); + if (aaa) + { + server = aaa; + } + return charon->eap->create_instance(charon->eap, type, vendor, + role, server, peer); +} + +/** + * Initiate EAP conversation as server + */ +static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this, + bool do_identity) +{ + auth_cfg_t *auth; + eap_type_t type; + identification_t *id; + u_int32_t vendor; + eap_payload_t *out; + char *action; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + + /* initiate EAP-Identity exchange if required */ + if (!this->eap_identity && do_identity) + { + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (id) + { + if (id->get_type(id) == ID_ANY) + { + this->method = load_method(this, EAP_IDENTITY, 0, EAP_SERVER); + if (this->method) + { + if (this->method->initiate(this->method, &out) == NEED_MORE) + { + DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", + eap_type_names, EAP_IDENTITY, + this->method->get_identifier(this->method)); + return out; + } + this->method->destroy(this->method); + } + DBG1(DBG_IKE, "EAP-Identity request configured, " + "but not supported"); + } + else + { + DBG1(DBG_IKE, "using configured EAP-Identity %Y", id); + this->eap_identity = id->clone(id); + } + } + } + /* invoke real EAP method */ + type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + action = "loading"; + this->method = load_method(this, type, vendor, EAP_SERVER); + if (this->method) + { + action = "initiating"; + if (this->method->initiate(this->method, &out) == NEED_MORE) + { + type = this->method->get_type(this->method, &vendor); + if (vendor) + { + DBG1(DBG_IKE, "initiating EAP vendor type %d-%d method (id 0x%02X)", + type, vendor, out->get_identifier(out)); + } + else + { + DBG1(DBG_IKE, "initiating %N method (id 0x%02X)", eap_type_names, + type, out->get_identifier(out)); + } + return out; + } + /* type might have changed for virtual methods */ + type = this->method->get_type(this->method, &vendor); + } + if (vendor) + { + DBG1(DBG_IKE, "%s EAP vendor type %d-%d method failed", + action, type, vendor); + } + else + { + DBG1(DBG_IKE, "%s %N method failed", action, eap_type_names, type); + } + return eap_payload_create_code(EAP_FAILURE, 0); +} + +/** + * Replace the existing EAP-Identity in other auth config + */ +static void replace_eap_identity(private_eap_authenticator_t *this) +{ + identification_t *eap_identity; + auth_cfg_t *cfg; + + eap_identity = this->eap_identity->clone(this->eap_identity); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, eap_identity); +} + +/** + * Handle EAP exchange as server + */ +static eap_payload_t* server_process_eap(private_eap_authenticator_t *this, + eap_payload_t *in) +{ + eap_type_t type, received_type, conf_type; + u_int32_t vendor, received_vendor, conf_vendor; + eap_payload_t *out; + auth_cfg_t *auth; + + if (in->get_code(in) != EAP_RESPONSE) + { + DBG1(DBG_IKE, "received %N, sending %N", + eap_code_names, in->get_code(in), eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); + } + + type = this->method->get_type(this->method, &vendor); + received_type = in->get_type(in, &received_vendor); + if (type != received_type || vendor != received_vendor) + { + if (received_vendor == 0 && received_type == EAP_NAK) + { + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + if ((type == EAP_IDENTITY && !vendor) || + (type == conf_type && vendor == conf_vendor)) + { + DBG1(DBG_IKE, "received %N, sending %N", + eap_type_names, EAP_NAK, eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, + in->get_identifier(in)); + } + /* virtual methods handle NAKs in process() */ + } + else + { + DBG1(DBG_IKE, "received invalid EAP response, sending %N", + eap_code_names, EAP_FAILURE); + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); + } + } + + switch (this->method->process(this->method, in, &out)) + { + case NEED_MORE: + return out; + case SUCCESS: + if (!vendor && type == EAP_IDENTITY) + { + chunk_t data; + + if (this->method->get_msk(this->method, &data) == SUCCESS) + { + this->eap_identity = identification_create_from_data(data); + DBG1(DBG_IKE, "received EAP identity '%Y'", + this->eap_identity); + replace_eap_identity(this); + } + /* restart EAP exchange, but with real method */ + this->method->destroy(this->method); + return server_initiate_eap(this, FALSE); + } + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + this->msk = chunk_clone(this->msk); + } + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " + "%sMSK established", type, vendor, + this->msk.ptr ? "" : "no "); + } + else + { + DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", + eap_type_names, type, this->msk.ptr ? "" : "no "); + } + this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, + TRUE); + this->eap_complete = TRUE; + return eap_payload_create_code(EAP_SUCCESS, in->get_identifier(in)); + case FAILED: + default: + /* type might have changed for virtual methods */ + type = this->method->get_type(this->method, &vendor); + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d failed for " + "peer %Y", type, vendor, + this->ike_sa->get_other_id(this->ike_sa)); + } + else + { + DBG1(DBG_IKE, "EAP method %N failed for peer %Y", + eap_type_names, type, + this->ike_sa->get_other_id(this->ike_sa)); + } + return eap_payload_create_code(EAP_FAILURE, in->get_identifier(in)); + } +} + +/** + * Processing method for a peer + */ +static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, + eap_payload_t *in) +{ + eap_type_t type, conf_type; + u_int32_t vendor, conf_vendor; + auth_cfg_t *auth; + eap_payload_t *out; + identification_t *id; + + type = in->get_type(in, &vendor); + + if (!vendor && type == EAP_IDENTITY) + { + DESTROY_IF(this->eap_identity); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + id = auth->get(auth, AUTH_RULE_EAP_IDENTITY); + if (!id || id->get_type(id) == ID_ANY) + { + id = this->ike_sa->get_my_id(this->ike_sa); + } + DBG1(DBG_IKE, "server requested %N (id 0x%02X), sending '%Y'", + eap_type_names, type, in->get_identifier(in), id); + this->eap_identity = id->clone(id); + + this->method = load_method(this, type, vendor, EAP_PEER); + if (this->method) + { + if (this->method->process(this->method, in, &out) == SUCCESS) + { + this->method->destroy(this->method); + this->method = NULL; + return out; + } + this->method->destroy(this->method); + this->method = NULL; + } + /* FIXME: sending a Nak is not correct here as EAP_IDENTITY (1) is no + * EAP method (types 3-253, 255) */ + DBG1(DBG_IKE, "%N not supported, sending EAP_NAK", + eap_type_names, type); + return eap_payload_create_nak(in->get_identifier(in), 0, 0, FALSE); + } + if (this->method == NULL) + { + if (vendor) + { + DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ", + "(id 0x%02X)", type, vendor, in->get_identifier(in)); + } + else + { + DBG1(DBG_IKE, "server requested %N authentication (id 0x%02X)", + eap_type_names, type, in->get_identifier(in)); + } + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + conf_type = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE); + conf_vendor = (uintptr_t)auth->get(auth, AUTH_RULE_EAP_VENDOR); + if (conf_type != EAP_NAK && + (conf_type != type || conf_vendor != vendor)) + { + if (conf_vendor) + { + DBG1(DBG_IKE, "requesting EAP method %d-%d, sending EAP_NAK", + conf_type, conf_vendor); + } + else + { + DBG1(DBG_IKE, "requesting %N authentication, sending EAP_NAK", + eap_type_names, conf_type); + } + return eap_payload_create_nak(in->get_identifier(in), conf_type, + conf_vendor, in->is_expanded(in)); + } + this->method = load_method(this, type, vendor, EAP_PEER); + if (!this->method) + { + DBG1(DBG_IKE, "EAP method not supported, sending EAP_NAK"); + return eap_payload_create_nak(in->get_identifier(in), 0, 0, + in->is_expanded(in)); + } + } + + type = this->method->get_type(this->method, &vendor); + + if (this->method->process(this->method, in, &out) == NEED_MORE) + { /* client methods should never return SUCCESS */ + return out; + } + + if (vendor) + { + DBG1(DBG_IKE, "vendor specific EAP method %d-%d failed", type, vendor); + } + else + { + DBG1(DBG_IKE, "%N method failed", eap_type_names, type); + } + return NULL; +} + +/** + * Verify AUTH payload + */ +static bool verify_auth(private_eap_authenticator_t *this, message_t *message, + chunk_t nonce, chunk_t init) +{ + auth_payload_t *auth_payload; + chunk_t auth_data, recv_auth_data; + identification_t *other_id; + auth_cfg_t *auth; + keymat_v2_t *keymat; + + auth_payload = (auth_payload_t*)message->get_payload(message, + AUTHENTICATION); + if (!auth_payload) + { + DBG1(DBG_IKE, "AUTH payload missing"); + return FALSE; + } + other_id = this->ike_sa->get_other_id(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_psk_sig(keymat, TRUE, init, nonce, + this->msk, other_id, this->reserved, &auth_data)) + { + return FALSE; + } + recv_auth_data = auth_payload->get_data(auth_payload); + if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) + { + DBG1(DBG_IKE, "verification of AUTH payload with%s EAP MSK failed", + this->msk.ptr ? "" : "out"); + chunk_free(&auth_data); + return FALSE; + } + chunk_free(&auth_data); + + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + other_id, auth_class_names, AUTH_CLASS_EAP); + this->auth_complete = TRUE; + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); + return TRUE; +} + +/** + * Build AUTH payload + */ +static bool build_auth(private_eap_authenticator_t *this, message_t *message, + chunk_t nonce, chunk_t init) +{ + auth_payload_t *auth_payload; + identification_t *my_id; + chunk_t auth_data; + keymat_v2_t *keymat; + + my_id = this->ike_sa->get_my_id(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", + my_id, auth_class_names, AUTH_CLASS_EAP); + + if (!keymat->get_psk_sig(keymat, FALSE, init, nonce, + this->msk, my_id, this->reserved, &auth_data)) + { + return FALSE; + } + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, AUTH_PSK); + auth_payload->set_data(auth_payload, auth_data); + message->add_payload(message, (payload_t*)auth_payload); + chunk_free(&auth_data); + return TRUE; +} + +METHOD(authenticator_t, process_server, status_t, + private_eap_authenticator_t *this, message_t *message) +{ + eap_payload_t *eap_payload; + + if (this->eap_complete) + { + if (!verify_auth(this, message, this->sent_nonce, this->received_init)) + { + return FAILED; + } + return NEED_MORE; + } + + if (!this->method) + { + this->eap_payload = server_initiate_eap(this, TRUE); + } + else + { + eap_payload = (eap_payload_t*)message->get_payload(message, + EXTENSIBLE_AUTHENTICATION); + if (!eap_payload) + { + return FAILED; + } + this->eap_payload = server_process_eap(this, eap_payload); + } + return NEED_MORE; +} + +METHOD(authenticator_t, build_server, status_t, + private_eap_authenticator_t *this, message_t *message) +{ + if (this->eap_payload) + { + eap_code_t code; + + code = this->eap_payload->get_code(this->eap_payload); + message->add_payload(message, (payload_t*)this->eap_payload); + this->eap_payload = NULL; + if (code == EAP_FAILURE) + { + return FAILED; + } + return NEED_MORE; + } + if (this->eap_complete && this->auth_complete && + build_auth(this, message, this->received_nonce, this->sent_init)) + { + return SUCCESS; + } + return FAILED; +} + +METHOD(authenticator_t, process_client, status_t, + private_eap_authenticator_t *this, message_t *message) +{ + eap_payload_t *eap_payload; + + if (this->eap_complete) + { + if (!verify_auth(this, message, this->sent_nonce, this->received_init)) + { + return FAILED; + } + if (this->require_mutual && !this->method->is_mutual(this->method)) + { /* we require mutual authentication due to EAP-only */ + u_int32_t vendor; + + DBG1(DBG_IKE, "EAP-only authentication requires a mutual and " + "MSK deriving EAP method, but %N is not", + eap_type_names, this->method->get_type(this->method, &vendor)); + return FAILED; + } + return SUCCESS; + } + + eap_payload = (eap_payload_t*)message->get_payload(message, + EXTENSIBLE_AUTHENTICATION); + if (eap_payload) + { + switch (eap_payload->get_code(eap_payload)) + { + case EAP_REQUEST: + { + this->eap_payload = client_process_eap(this, eap_payload); + if (this->eap_payload) + { + return NEED_MORE; + } + return FAILED; + } + case EAP_SUCCESS: + { + eap_type_t type; + u_int32_t vendor; + auth_cfg_t *cfg; + + if (this->method->get_msk(this->method, &this->msk) == SUCCESS) + { + this->msk = chunk_clone(this->msk); + } + type = this->method->get_type(this->method, &vendor); + if (vendor) + { + DBG1(DBG_IKE, "EAP vendor specific method %d-%d succeeded, " + "%sMSK established", type, vendor, + this->msk.ptr ? "" : "no "); + } + else + { + DBG1(DBG_IKE, "EAP method %N succeeded, %sMSK established", + eap_type_names, type, this->msk.ptr ? "" : "no "); + } + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->add(cfg, AUTH_RULE_EAP_TYPE, type); + if (vendor) + { + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, vendor); + } + this->eap_complete = TRUE; + return NEED_MORE; + } + case EAP_FAILURE: + default: + { + DBG1(DBG_IKE, "received %N, EAP authentication failed", + eap_code_names, eap_payload->get_code(eap_payload)); + return FAILED; + } + } + } + return FAILED; +} + +METHOD(authenticator_t, build_client, status_t, + private_eap_authenticator_t *this, message_t *message) +{ + if (this->eap_payload) + { + message->add_payload(message, (payload_t*)this->eap_payload); + this->eap_payload = NULL; + return NEED_MORE; + } + if (this->eap_complete && + build_auth(this, message, this->received_nonce, this->sent_init)) + { + return NEED_MORE; + } + return NEED_MORE; +} + +METHOD(authenticator_t, is_mutual, bool, + private_eap_authenticator_t *this) +{ + /* we don't know yet, but insist on it after EAP is complete */ + this->require_mutual = TRUE; + return TRUE; +} + +METHOD(authenticator_t, destroy, void, + private_eap_authenticator_t *this) +{ + DESTROY_IF(this->method); + DESTROY_IF(this->eap_payload); + DESTROY_IF(this->eap_identity); + chunk_free(&this->msk); + free(this); +} + +/* + * Described in header. + */ +eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]) +{ + private_eap_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build_client, + .process = _process_client, + .is_mutual = _is_mutual, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .received_init = received_init, + .received_nonce = received_nonce, + .sent_init = sent_init, + .sent_nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} + +/* + * Described in header. + */ +eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]) +{ + private_eap_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build_server, + .process = _process_server, + .is_mutual = _is_mutual, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .received_init = received_init, + .received_nonce = received_nonce, + .sent_init = sent_init, + .sent_nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.h b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.h new file mode 100644 index 000000000..d81ebd562 --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup eap_authenticator eap_authenticator + * @{ @ingroup authenticators_v2 + */ + +#ifndef EAP_AUTHENTICATOR_H_ +#define EAP_AUTHENTICATOR_H_ + +typedef struct eap_authenticator_t eap_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using EAP authentication. + * + * Authentication using EAP involves the most complex authenticator. It stays + * alive over multiple ike_auth transactions and handles multiple EAP + * messages. + * + * @verbatim + ike_sa_init + -------------------------> + <------------------------- + followed by multiple ike_auth: + + +--------+ +--------+ + | EAP | IDi, [IDr,] SA, TS | EAP | + | client | ---------------------------> | server | + | | ID, AUTH, EAP | | + | | <--------------------------- | | + | | EAP | | + | | ---------------------------> | | + | | EAP | | + | | <--------------------------- | | + | | EAP | | + | | ---------------------------> | | + | | EAP(SUCCESS) | | + | | <--------------------------- | | + | | AUTH | | If EAP establishes + | | ---------------------------> | | a session key, AUTH + | | AUTH, SA, TS | | payloads use this + | | <--------------------------- | | key, not SK_pi/pr + +--------+ +--------+ + + @endverbatim + */ +struct eap_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to authenticate against an EAP server. + * + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return EAP authenticator + */ +eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]); + +/** + * Create an authenticator to authenticate EAP clients. + * + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return EAP authenticator + */ +eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_nonce, + chunk_t received_init, chunk_t sent_init, + char reserved[3]); + +#endif /** EAP_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c new file mode 100644 index 000000000..997efe359 --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "psk_authenticator.h" + +#include +#include +#include + +typedef struct private_psk_authenticator_t private_psk_authenticator_t; + +/** + * Private data of an psk_authenticator_t object. + */ +struct private_psk_authenticator_t { + + /** + * Public authenticator_t interface. + */ + psk_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * nonce to include in AUTH calculation + */ + chunk_t nonce; + + /** + * IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t ike_sa_init; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; +}; + +METHOD(authenticator_t, build, status_t, + private_psk_authenticator_t *this, message_t *message) +{ + identification_t *my_id, *other_id; + auth_payload_t *auth_payload; + shared_key_t *key; + chunk_t auth_data; + keymat_v2_t *keymat; + + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", + my_id, auth_method_names, AUTH_PSK); + key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, other_id); + if (key == NULL) + { + DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id); + return NOT_FOUND; + } + if (!keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, this->nonce, + key->get_key(key), my_id, this->reserved, &auth_data)) + { + key->destroy(key); + return FAILED; + } + key->destroy(key); + DBG2(DBG_IKE, "successfully created shared key MAC"); + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, AUTH_PSK); + auth_payload->set_data(auth_payload, auth_data); + chunk_free(&auth_data); + message->add_payload(message, (payload_t*)auth_payload); + + return SUCCESS; +} + +METHOD(authenticator_t, process, status_t, + private_psk_authenticator_t *this, message_t *message) +{ + chunk_t auth_data, recv_auth_data; + identification_t *my_id, *other_id; + auth_payload_t *auth_payload; + auth_cfg_t *auth; + shared_key_t *key; + enumerator_t *enumerator; + bool authenticated = FALSE; + int keys_found = 0; + keymat_v2_t *keymat; + + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (!auth_payload) + { + return FAILED; + } + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + recv_auth_data = auth_payload->get_data(auth_payload); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_IKE, my_id, other_id); + while (!authenticated && enumerator->enumerate(enumerator, &key, NULL, NULL)) + { + keys_found++; + + if (!keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, this->nonce, + key->get_key(key), other_id, this->reserved, &auth_data)) + { + continue; + } + if (auth_data.len && chunk_equals(auth_data, recv_auth_data)) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + other_id, auth_method_names, AUTH_PSK); + authenticated = TRUE; + } + chunk_free(&auth_data); + } + enumerator->destroy(enumerator); + + if (!authenticated) + { + if (keys_found == 0) + { + DBG1(DBG_IKE, "no shared key found for '%Y' - '%Y'", my_id, other_id); + return NOT_FOUND; + } + DBG1(DBG_IKE, "tried %d shared key%s for '%Y' - '%Y', but MAC mismatched", + keys_found, keys_found == 1 ? "" : "s", my_id, other_id); + return FAILED; + } + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + return SUCCESS; +} + +METHOD(authenticator_t, destroy, void, + private_psk_authenticator_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]) +{ + private_psk_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = (void*)return_failed, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = sent_init, + .nonce = received_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} + +/* + * Described in header. + */ +psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]) +{ + private_psk_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = (void*)return_failed, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = received_init, + .nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/authenticators/psk_authenticator.h b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.h new file mode 100644 index 000000000..91c534145 --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup psk_authenticator psk_authenticator + * @{ @ingroup authenticators_v2 + */ + +#ifndef PSK_AUTHENTICATOR_H_ +#define PSK_AUTHENTICATOR_H_ + +typedef struct psk_authenticator_t psk_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using pre-shared keys. + */ +struct psk_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build PSK signatures. + * + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return PSK authenticator + */ +psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]); + +/** + * Create an authenticator to verify PSK signatures. + * + * @param ike_sa associated ike_sa + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return PSK authenticator + */ +psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]); + +#endif /** PSK_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c new file mode 100644 index 000000000..5ceff40ba --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pubkey_authenticator.h" + +#include +#include +#include + +typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t; + +/** + * Private data of an pubkey_authenticator_t object. + */ +struct private_pubkey_authenticator_t { + + /** + * Public authenticator_t interface. + */ + pubkey_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * nonce to include in AUTH calculation + */ + chunk_t nonce; + + /** + * IKE_SA_INIT message data to include in AUTH calculation + */ + chunk_t ike_sa_init; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; +}; + +METHOD(authenticator_t, build, status_t, + private_pubkey_authenticator_t *this, message_t *message) +{ + chunk_t octets = chunk_empty, auth_data; + status_t status = FAILED; + private_key_t *private; + identification_t *id; + auth_cfg_t *auth; + auth_payload_t *auth_payload; + auth_method_t auth_method; + signature_scheme_t scheme; + keymat_v2_t *keymat; + + id = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth); + if (private == NULL) + { + DBG1(DBG_IKE, "no private key found for '%Y'", id); + return NOT_FOUND; + } + + switch (private->get_type(private)) + { + case KEY_RSA: + /* we currently use always SHA1 for signatures, + * TODO: support other hashes depending on configuration/auth */ + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + auth_method = AUTH_RSA; + break; + case KEY_ECDSA: + /* we try to deduct the signature scheme from the keysize */ + switch (private->get_keysize(private)) + { + case 256: + scheme = SIGN_ECDSA_256; + auth_method = AUTH_ECDSA_256; + break; + case 384: + scheme = SIGN_ECDSA_384; + auth_method = AUTH_ECDSA_384; + break; + case 521: + scheme = SIGN_ECDSA_521; + auth_method = AUTH_ECDSA_521; + break; + default: + DBG1(DBG_IKE, "%d bit ECDSA private key size not supported", + private->get_keysize(private)); + return status; + } + break; + default: + DBG1(DBG_IKE, "private key of type %N not supported", + key_type_names, private->get_type(private)); + return status; + } + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + if (keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, + this->nonce, id, this->reserved, &octets) && + private->sign(private, scheme, octets, &auth_data)) + { + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, auth_method); + auth_payload->set_data(auth_payload, auth_data); + chunk_free(&auth_data); + message->add_payload(message, (payload_t*)auth_payload); + status = SUCCESS; + } + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N %s", id, + auth_method_names, auth_method, + (status == SUCCESS)? "successful":"failed"); + chunk_free(&octets); + private->destroy(private); + + return status; +} + +METHOD(authenticator_t, process, status_t, + private_pubkey_authenticator_t *this, message_t *message) +{ + public_key_t *public; + auth_method_t auth_method; + auth_payload_t *auth_payload; + chunk_t auth_data, octets; + identification_t *id; + auth_cfg_t *auth, *current_auth; + enumerator_t *enumerator; + key_type_t key_type = KEY_ECDSA; + signature_scheme_t scheme; + status_t status = NOT_FOUND; + keymat_v2_t *keymat; + + auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + if (!auth_payload) + { + return FAILED; + } + auth_method = auth_payload->get_auth_method(auth_payload); + switch (auth_method) + { + case AUTH_RSA: + /* We currently accept SHA1 signatures only + * TODO: allow other hash algorithms and note it in "auth" */ + key_type = KEY_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + break; + case AUTH_ECDSA_256: + scheme = SIGN_ECDSA_256; + break; + case AUTH_ECDSA_384: + scheme = SIGN_ECDSA_384; + break; + case AUTH_ECDSA_521: + scheme = SIGN_ECDSA_521; + break; + default: + return INVALID_ARG; + } + auth_data = auth_payload->get_data(auth_payload); + id = this->ike_sa->get_other_id(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); + if (!keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init, + this->nonce, id, this->reserved, &octets)) + { + return FAILED; + } + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, + key_type, id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) + { + if (public->verify(public, scheme, octets, auth_data)) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + id, auth_method_names, auth_method); + status = SUCCESS; + auth->merge(auth, current_auth, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + break; + } + else + { + status = FAILED; + DBG1(DBG_IKE, "signature validation failed, looking for another key"); + } + } + enumerator->destroy(enumerator); + chunk_free(&octets); + if (status == NOT_FOUND) + { + DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", + key_type_names, key_type, id); + } + return status; +} + +METHOD(authenticator_t, destroy, void, + private_pubkey_authenticator_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]) +{ + private_pubkey_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = (void*)return_failed, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = sent_init, + .nonce = received_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} + +/* + * Described in header. + */ +pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]) +{ + private_pubkey_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = (void*)return_failed, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = received_init, + .nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h new file mode 100644 index 000000000..82bfea23b --- /dev/null +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pubkey_authenticator pubkey_authenticator + * @{ @ingroup authenticators_v2 + */ + +#ifndef PUBKEY_AUTHENTICATOR_H_ +#define PUBKEY_AUTHENTICATOR_H_ + +typedef struct pubkey_authenticator_t pubkey_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using public key authenitcation. + */ +struct pubkey_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build public key signatures. + * + * @param ike_sa associated ike_sa + * @param received_nonce nonce received in IKE_SA_INIT + * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return public key authenticator + */ +pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]); + +/** + * Create an authenticator to verify public key signatures. + * + * @param ike_sa associated ike_sa + * @param sent_nonce nonce sent in IKE_SA_INIT + * @param received_init received IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload + * @return public key authenticator + */ +pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]); + +#endif /** PUBKEY_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/connect_manager.c b/src/libcharon/sa/ikev2/connect_manager.c new file mode 100644 index 000000000..5fdcea1ab --- /dev/null +++ b/src/libcharon/sa/ikev2/connect_manager.c @@ -0,0 +1,1615 @@ +/* + * Copyright (C) 2007-2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "connect_manager.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +/* base timeout + * the check interval is ME_INTERVAL */ +#define ME_INTERVAL 25 /* ms */ +/* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions + * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */ +/* number of initial retransmissions sent in short interval */ +#define ME_BOOST 2 +/* base for retransmissions */ +#define ME_RETRANS_BASE 1.8 +/* max number of retransmissions */ +#define ME_MAX_RETRANS 13 + +/* time to wait before the initiator finishes the connectivity checks after + * the first check has succeeded */ +#define ME_WAIT_TO_FINISH 1000 /* ms */ + +typedef struct private_connect_manager_t private_connect_manager_t; + +/** + * Additional private members of connect_manager_t. + */ +struct private_connect_manager_t { + /** + * Public interface of connect_manager_t. + */ + connect_manager_t public; + + /** + * Lock for exclusivly accessing the manager. + */ + mutex_t *mutex; + + /** + * Hasher to generate signatures + */ + hasher_t *hasher; + + /** + * Linked list with initiated mediated connections + */ + linked_list_t *initiated; + + /** + * Linked list with checklists (hash table with connect ID as key would + * be better). + */ + linked_list_t *checklists; +}; + +typedef enum check_state_t check_state_t; + +enum check_state_t { + CHECK_NONE, + CHECK_WAITING, + CHECK_IN_PROGRESS, + CHECK_SUCCEEDED, + CHECK_FAILED +}; + +typedef struct endpoint_pair_t endpoint_pair_t; + +/** + * An entry in the check list. + */ +struct endpoint_pair_t { + /** pair id */ + u_int32_t id; + + /** priority */ + u_int64_t priority; + + /** local endpoint */ + host_t *local; + + /** remote endpoint */ + host_t *remote; + + /** state */ + check_state_t state; + + /** number of retransmissions */ + u_int32_t retransmitted; + + /** the generated packet */ + packet_t *packet; +}; + +/** + * Destroys an endpoint pair + */ +static void endpoint_pair_destroy(endpoint_pair_t *this) +{ + DESTROY_IF(this->local); + DESTROY_IF(this->remote); + DESTROY_IF(this->packet); + free(this); +} + +/** + * Creates a new entry for the list. + */ +static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator, + endpoint_notify_t *responder, bool initiator_is_local) +{ + endpoint_pair_t *this; + + u_int32_t pi = initiator->get_priority(initiator); + u_int32_t pr = responder->get_priority(responder); + + INIT(this, + .priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) + + (pi > pr ? 1 : 0), + .local = initiator_is_local ? initiator->get_base(initiator) + : responder->get_base(responder), + .remote = initiator_is_local ? responder->get_host(responder) + : initiator->get_host(initiator), + .state = CHECK_WAITING, + ); + + this->local = this->local->clone(this->local); + this->remote = this->remote->clone(this->remote); + + return this; +} + + +typedef struct check_list_t check_list_t; + +/** + * An entry in the linked list. + */ +struct check_list_t { + + struct { + /** initiator's id */ + identification_t *id; + + /** initiator's key */ + chunk_t key; + + /** initiator's endpoints */ + linked_list_t *endpoints; + } initiator; + + struct { + /** responder's id */ + identification_t *id; + + /** responder's key */ + chunk_t key; + + /** responder's endpoints */ + linked_list_t *endpoints; + } responder; + + /** connect id */ + chunk_t connect_id; + + /** list of endpoint pairs */ + linked_list_t *pairs; + + /** pairs queued for triggered checks */ + linked_list_t *triggered; + + /** state */ + check_state_t state; + + /** TRUE if this is the initiator */ + bool is_initiator; + + /** TRUE if the initiator is finishing the checks */ + bool is_finishing; + + /** the current sender job */ + job_t *sender; + +}; + +/** + * Destroys a checklist + */ +static void check_list_destroy(check_list_t *this) +{ + DESTROY_IF(this->initiator.id); + DESTROY_IF(this->responder.id); + + chunk_free(&this->connect_id); + chunk_free(&this->initiator.key); + chunk_free(&this->responder.key); + + DESTROY_OFFSET_IF(this->initiator.endpoints, + offsetof(endpoint_notify_t, destroy)); + DESTROY_OFFSET_IF(this->responder.endpoints, + offsetof(endpoint_notify_t, destroy)); + + DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy); + /* this list contains some of the elements contained in this->pairs */ + DESTROY_IF(this->triggered); + + free(this); +} + +/** + * Creates a new checklist + */ +static check_list_t *check_list_create(identification_t *initiator, + identification_t *responder, + chunk_t connect_id, + chunk_t initiator_key, + linked_list_t *initiator_endpoints, + bool is_initiator) +{ + check_list_t *this; + + INIT(this, + .connect_id = chunk_clone(connect_id), + .initiator = { + .id = initiator->clone(initiator), + .key = chunk_clone(initiator_key), + .endpoints = initiator_endpoints->clone_offset(initiator_endpoints, + offsetof(endpoint_notify_t, clone)), + }, + .responder = { + .id = responder->clone(responder), + }, + .pairs = linked_list_create(), + .triggered = linked_list_create(), + .state = CHECK_NONE, + .is_initiator = is_initiator, + ); + + return this; +} + +typedef struct initiated_t initiated_t; + +/** + * For an initiator, the data stored about initiated mediation connections + */ +struct initiated_t { + /** my id */ + identification_t *id; + + /** peer id */ + identification_t *peer_id; + + /** list of mediated sas */ + linked_list_t *mediated; +}; + +/** + * Destroys a queued initiation + */ +static void initiated_destroy(initiated_t *this) +{ + DESTROY_IF(this->id); + DESTROY_IF(this->peer_id); + this->mediated->destroy_offset(this->mediated, + offsetof(ike_sa_id_t, destroy)); + free(this); +} + +/** + * Creates a queued initiation + */ +static initiated_t *initiated_create(identification_t *id, + identification_t *peer_id) +{ + initiated_t *this; + + INIT(this, + .id = id->clone(id), + .peer_id = peer_id->clone(peer_id), + .mediated = linked_list_create(), + ); + + return this; +} + + +typedef struct check_t check_t; + +/** + * Data exchanged in a connectivity check + */ +struct check_t { + /** message id */ + u_int32_t mid; + + /** source of the connectivity check */ + host_t *src; + + /** destination of the connectivity check */ + host_t *dst; + + /** connect id */ + chunk_t connect_id; + + /** endpoint */ + endpoint_notify_t *endpoint; + + /** raw endpoint payload (to verify the signature) */ + chunk_t endpoint_raw; + + /** connect auth */ + chunk_t auth; +}; + +/** + * Destroys a connectivity check + */ +static void check_destroy(check_t *this) +{ + chunk_free(&this->connect_id); + chunk_free(&this->endpoint_raw); + chunk_free(&this->auth); + DESTROY_IF(this->src); + DESTROY_IF(this->dst); + DESTROY_IF(this->endpoint); + free(this); +} + +/** + * Creates a new connectivity check + */ +static check_t *check_create() +{ + check_t *this; + + INIT(this, + .mid = 0, + ); + + return this; +} + +typedef struct callback_data_t callback_data_t; + +/** + * Data required by several callback jobs used in this file + */ +struct callback_data_t { + /** connect manager */ + private_connect_manager_t *connect_manager; + + /** connect id */ + chunk_t connect_id; + + /** message (pair) id */ + u_int32_t mid; +}; + +/** + * Destroys a callback data object + */ +static void callback_data_destroy(callback_data_t *this) +{ + chunk_free(&this->connect_id); + free(this); +} + +/** + * Creates a new callback data object + */ +static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager, + chunk_t connect_id) +{ + callback_data_t *this; + INIT(this, + .connect_manager = connect_manager, + .connect_id = chunk_clone(connect_id), + .mid = 0, + ); + return this; +} + +/** + * Creates a new retransmission data object + */ +static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager, + chunk_t connect_id, u_int32_t mid) +{ + callback_data_t *this = callback_data_create(connect_manager, connect_id); + this->mid = mid; + return this; +} + +typedef struct initiate_data_t initiate_data_t; + +/** + * Data required by the initiate mediated + */ +struct initiate_data_t { + /** checklist */ + check_list_t *checklist; + + /** waiting mediated connections */ + initiated_t *initiated; +}; + +/** + * Destroys a initiate data object + */ +static void initiate_data_destroy(initiate_data_t *this) +{ + check_list_destroy(this->checklist); + initiated_destroy(this->initiated); + free(this); +} + +/** + * Creates a new initiate data object + */ +static initiate_data_t *initiate_data_create(check_list_t *checklist, + initiated_t *initiated) +{ + initiate_data_t *this; + INIT(this, + .checklist = checklist, + .initiated = initiated, + ); + return this; +} + +/** + * Find an initiated connection by the peers' ids + */ +static bool match_initiated_by_ids(initiated_t *current, identification_t *id, + identification_t *peer_id) +{ + return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id); +} + +static status_t get_initiated_by_ids(private_connect_manager_t *this, + identification_t *id, + identification_t *peer_id, + initiated_t **initiated) +{ + return this->initiated->find_first(this->initiated, + (linked_list_match_t)match_initiated_by_ids, + (void**)initiated, id, peer_id); +} + +/** + * Removes data about initiated connections + */ +static void remove_initiated(private_connect_manager_t *this, + initiated_t *initiated) +{ + enumerator_t *enumerator; + initiated_t *current; + + enumerator = this->initiated->create_enumerator(this->initiated); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current == initiated) + { + this->initiated->remove_at(this->initiated, enumerator); + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Find the checklist with a specific connect ID + */ +static bool match_checklist_by_id(check_list_t *current, chunk_t *connect_id) +{ + return chunk_equals(*connect_id, current->connect_id); +} + +static status_t get_checklist_by_id(private_connect_manager_t *this, + chunk_t connect_id, + check_list_t **check_list) +{ + return this->checklists->find_first(this->checklists, + (linked_list_match_t)match_checklist_by_id, + (void**)check_list, &connect_id); +} + +/** + * Removes a checklist + */ +static void remove_checklist(private_connect_manager_t *this, + check_list_t *checklist) +{ + enumerator_t *enumerator; + check_list_t *current; + + enumerator = this->checklists->create_enumerator(this->checklists); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current == checklist) + { + this->checklists->remove_at(this->checklists, enumerator); + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Checks if a list of endpoint_notify_t contains a certain host_t + */ +static bool match_endpoint_by_host(endpoint_notify_t *current, host_t *host) +{ + return host->equals(host, current->get_host(current)); +} + +static status_t endpoints_contain(linked_list_t *endpoints, host_t *host, + endpoint_notify_t **endpoint) +{ + return endpoints->find_first(endpoints, + (linked_list_match_t)match_endpoint_by_host, + (void**)endpoint, host); +} + +/** + * Inserts an endpoint pair into a list of pairs ordered by priority (high to low) + */ +static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) +{ + enumerator_t *enumerator = pairs->create_enumerator(pairs); + endpoint_pair_t *current; + while (enumerator->enumerate(enumerator, (void**)¤t) && + current->priority >= pair->priority) + { + continue; + } + pairs->insert_before(pairs, enumerator, pair); + enumerator->destroy(enumerator); +} + +/** + * Searches a list of endpoint_pair_t for a pair with specific host_ts + */ +static bool match_pair_by_hosts(endpoint_pair_t *current, host_t *local, + host_t *remote) +{ + return local->equals(local, current->local) && remote->equals(remote, current->remote); +} + +static status_t get_pair_by_hosts(linked_list_t *pairs, host_t *local, + host_t *remote, endpoint_pair_t **pair) +{ + return pairs->find_first(pairs, (linked_list_match_t)match_pair_by_hosts, + (void**)pair, local, remote); +} + +static bool match_pair_by_id(endpoint_pair_t *current, u_int32_t *id) +{ + return current->id == *id; +} + +/** + * Searches for a pair with a specific id + */ +static status_t get_pair_by_id(check_list_t *checklist, u_int32_t id, + endpoint_pair_t **pair) +{ + return checklist->pairs->find_first(checklist->pairs, + (linked_list_match_t)match_pair_by_id, + (void**)pair, &id); +} + +static bool match_succeeded_pair(endpoint_pair_t *current) +{ + return current->state == CHECK_SUCCEEDED; +} + +/** + * Returns the best pair of state CHECK_SUCCEEDED from a checklist. + */ +static status_t get_best_valid_pair(check_list_t *checklist, + endpoint_pair_t **pair) +{ + return checklist->pairs->find_first(checklist->pairs, + (linked_list_match_t)match_succeeded_pair, + (void**)pair); +} + +static bool match_waiting_pair(endpoint_pair_t *current) +{ + return current->state == CHECK_WAITING; +} + +/** + * Returns and *removes* the first triggered pair in state CHECK_WAITING. + */ +static status_t get_triggered_pair(check_list_t *checklist, + endpoint_pair_t **pair) +{ + enumerator_t *enumerator; + endpoint_pair_t *current; + status_t status = NOT_FOUND; + + enumerator = checklist->triggered->create_enumerator(checklist->triggered); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + checklist->triggered->remove_at(checklist->triggered, enumerator); + + if (current->state == CHECK_WAITING) + { + if (pair) + { + *pair = current; + } + status = SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + + return status; +} + +/** + * Prints all the pairs on a checklist + */ +static void print_checklist(check_list_t *checklist) +{ + enumerator_t *enumerator; + endpoint_pair_t *current; + + DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id); + enumerator = checklist->pairs->create_enumerator(checklist->pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote, + current->priority); + } + enumerator->destroy(enumerator); +} + +/** + * Prunes identical pairs with lower priority from the list + * Note: this function also numbers the remaining pairs serially + */ +static void prune_pairs(linked_list_t *pairs) +{ + enumerator_t *enumerator, *search; + endpoint_pair_t *current, *other; + u_int32_t id = 0; + + enumerator = pairs->create_enumerator(pairs); + search = pairs->create_enumerator(pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + current->id = ++id; + + while (search->enumerate(search, (void**)&other)) + { + if (current == other) + { + continue; + } + + if (current->local->equals(current->local, other->local) && + current->remote->equals(current->remote, other->remote)) + { + /* since the list of pairs is sorted by priority in descending + * order, and we iterate the list from the beginning, we are + * sure that the priority of 'other' is lower than that of + * 'current', remove it */ + DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d", + other->local, other->remote, other->priority); + pairs->remove_at(pairs, search); + endpoint_pair_destroy(other); + } + } + pairs->reset_enumerator(pairs, search); + } + search->destroy(search); + enumerator->destroy(enumerator); +} + +/** + * Builds a list of endpoint pairs + */ +static void build_pairs(check_list_t *checklist) +{ + /* FIXME: limit endpoints and pairs */ + enumerator_t *enumerator_i, *enumerator_r; + endpoint_notify_t *initiator, *responder; + + enumerator_i = checklist->initiator.endpoints->create_enumerator( + checklist->initiator.endpoints); + while (enumerator_i->enumerate(enumerator_i, (void**)&initiator)) + { + enumerator_r = checklist->responder.endpoints->create_enumerator( + checklist->responder.endpoints); + while (enumerator_r->enumerate(enumerator_r, (void**)&responder)) + { + if (initiator->get_family(initiator) != responder->get_family(responder)) + { + continue; + } + + insert_pair_by_priority(checklist->pairs, endpoint_pair_create( + initiator, responder, checklist->is_initiator)); + } + enumerator_r->destroy(enumerator_r); + } + enumerator_i->destroy(enumerator_i); + + print_checklist(checklist); + + prune_pairs(checklist->pairs); +} + +/** + * Processes the payloads of a connectivity check and returns the extracted data + */ +static status_t process_payloads(message_t *message, check_t *check) +{ + enumerator_t *enumerator; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) != NOTIFY) + { + DBG1(DBG_IKE, "ignoring payload of type '%N' while processing " + "connectivity check", payload_type_names, + payload->get_type(payload)); + continue; + } + + notify_payload_t *notify = (notify_payload_t*)payload; + + switch (notify->get_notify_type(notify)) + { + case ME_ENDPOINT: + { + if (check->endpoint) + { + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_ENDPOINT notifies"); + break; + } + + endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify); + if (!endpoint) + { + DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify"); + break; + } + check->endpoint = endpoint; + check->endpoint_raw = chunk_clone(notify->get_notification_data(notify)); + DBG2(DBG_IKE, "received ME_ENDPOINT notify"); + break; + } + case ME_CONNECTID: + { + if (check->connect_id.ptr) + { + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_CONNECTID notifies"); + break; + } + check->connect_id = chunk_clone(notify->get_notification_data(notify)); + DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id); + break; + } + case ME_CONNECTAUTH: + { + if (check->auth.ptr) + { + DBG1(DBG_IKE, "connectivity check contains multiple " + "ME_CONNECTAUTH notifies"); + break; + } + check->auth = chunk_clone(notify->get_notification_data(notify)); + DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth); + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr) + { + DBG1(DBG_IKE, "at least one required payload was missing from the " + "connectivity check"); + return FAILED; + } + + return SUCCESS; +} + +/** + * Builds the signature for a connectivity check + */ +static chunk_t build_signature(private_connect_manager_t *this, + check_list_t *checklist, check_t *check, bool outbound) +{ + u_int32_t mid; + chunk_t mid_chunk, key_chunk, sig_chunk; + chunk_t sig_hash; + + mid = htonl(check->mid); + mid_chunk = chunk_from_thing(mid); + + key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound) + ? checklist->initiator.key : checklist->responder.key; + + /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */ + sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, + check->endpoint_raw, key_chunk); + if (!this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash)) + { + sig_hash = chunk_empty; + } + DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk); + DBG3(DBG_IKE, "sig_hash %#B", &sig_hash); + + chunk_free(&sig_chunk); + return sig_hash; +} + +static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair); +static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, u_int32_t time); +static void finish_checks(private_connect_manager_t *this, check_list_t *checklist); + +/** + * After one of the initiator's pairs has succeeded we finish the checks without + * waiting for all the timeouts + */ +static job_requeue_t initiator_finish(callback_data_t *data) +{ + private_connect_manager_t *this = data->connect_manager; + + this->mutex->lock(this->mutex); + + check_list_t *checklist; + if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish " + "connectivity checks", &data->connect_id); + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; + } + + finish_checks(this, checklist); + + this->mutex->unlock(this->mutex); + + return JOB_REQUEUE_NONE; +} + +/** + * Updates the state of the whole checklist + */ +static void update_checklist_state(private_connect_manager_t *this, + check_list_t *checklist) +{ + enumerator_t *enumerator; + endpoint_pair_t *current; + bool in_progress = FALSE, succeeded = FALSE; + + enumerator = checklist->pairs->create_enumerator(checklist->pairs); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + switch(current->state) + { + case CHECK_WAITING: + /* at least one is still waiting -> checklist remains + * in waiting state */ + enumerator->destroy(enumerator); + return; + case CHECK_IN_PROGRESS: + in_progress = TRUE; + break; + case CHECK_SUCCEEDED: + succeeded = TRUE; + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (checklist->is_initiator && succeeded && !checklist->is_finishing) + { + /* instead of waiting until all checks have finished (i.e. all + * retransmissions have failed) the initiator finishes the checks + * right after the first check has succeeded. to allow a probably + * better pair to succeed, we still wait a certain time */ + DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", + &checklist->connect_id); + + callback_data_t *data = callback_data_create(this, checklist->connect_id); + lib->scheduler->schedule_job_ms(lib->scheduler, + (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, + data, (callback_job_cleanup_t)callback_data_destroy, NULL), + ME_WAIT_TO_FINISH); + checklist->is_finishing = TRUE; + } + + if (in_progress) + { + checklist->state = CHECK_IN_PROGRESS; + } + else if (succeeded) + { + checklist->state = CHECK_SUCCEEDED; + } + else + { + checklist->state = CHECK_FAILED; + } +} + +/** + * This function is triggered for each sent check after a specific timeout + */ +static job_requeue_t retransmit(callback_data_t *data) +{ + private_connect_manager_t *this = data->connect_manager; + + this->mutex->lock(this->mutex); + + check_list_t *checklist; + if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit " + "connectivity check", &data->connect_id); + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; + } + + endpoint_pair_t *pair; + if (get_pair_by_id(checklist, data->mid, &pair) != SUCCESS) + { + DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit " + "connectivity check", data->mid); + goto retransmit_end; + } + + if (pair->state != CHECK_IN_PROGRESS) + { + DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't " + "retransmit the connectivity check", data->mid, pair->state); + goto retransmit_end; + } + + if (++pair->retransmitted > ME_MAX_RETRANS) + { + DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions", + data->mid, ME_MAX_RETRANS); + pair->state = CHECK_FAILED; + goto retransmit_end; + } + + charon->sender->send(charon->sender, pair->packet->clone(pair->packet)); + + queue_retransmission(this, checklist, pair); + +retransmit_end: + update_checklist_state(this, checklist); + + switch(checklist->state) + { + case CHECK_SUCCEEDED: + case CHECK_FAILED: + finish_checks(this, checklist); + break; + default: + break; + } + + this->mutex->unlock(this->mutex); + + /* we reschedule it manually */ + return JOB_REQUEUE_NONE; +} + +/** + * Queues a retransmission job + */ +static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair) +{ + callback_data_t *data; + job_t *job; + + data = retransmit_data_create(this, checklist->connect_id, pair->id); + job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, + (callback_job_cleanup_t)callback_data_destroy, NULL); + + u_int32_t retransmission = pair->retransmitted + 1; + u_int32_t rto = ME_INTERVAL; + if (retransmission > ME_BOOST) + { + rto = (u_int32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST)); + } + DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", + retransmission, pair->id, rto); + + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)job, rto); +} + +/** + * Sends a check + */ +static void send_check(private_connect_manager_t *this, check_list_t *checklist, + check_t *check, endpoint_pair_t *pair, bool request) +{ + message_t *message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); + message->set_message_id(message, check->mid); + message->set_exchange_type(message, INFORMATIONAL); + message->set_request(message, request); + message->set_destination(message, check->dst->clone(check->dst)); + message->set_source(message, check->src->clone(check->src)); + + ike_sa_id_t *ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0, + request); + message->set_ike_sa_id(message, ike_sa_id); + ike_sa_id->destroy(ike_sa_id); + + message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id); + DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id); + + notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint); + check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint)); + message->add_payload(message, (payload_t*)endpoint); + DBG2(DBG_IKE, "send ME_ENDPOINT notify"); + + check->auth = build_signature(this, checklist, check, TRUE); + message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth); + DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth); + + packet_t *packet; + if (message->generate(message, NULL, &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet->clone(packet)); + + if (request) + { + DESTROY_IF(pair->packet); + pair->packet = packet; + pair->retransmitted = 0; + queue_retransmission(this, checklist, pair); + } + else + { + packet->destroy(packet); + } + } + message->destroy(message); +} + +/** + * Queues a triggered check + */ +static void queue_triggered_check(private_connect_manager_t *this, + check_list_t *checklist, endpoint_pair_t *pair) +{ + DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id); + pair->state = CHECK_WAITING; + checklist->triggered->insert_last(checklist->triggered, pair); + + if (!checklist->sender) + { + /* if the sender is not running we restart it */ + schedule_checks(this, checklist, ME_INTERVAL); + } +} + +/** + * This function is triggered for each checklist at a specific interval + */ +static job_requeue_t sender(callback_data_t *data) +{ + private_connect_manager_t *this = data->connect_manager; + + this->mutex->lock(this->mutex); + + check_list_t *checklist; + if (get_checklist_by_id(this, data->connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send " + "connectivity check", &data->connect_id); + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; + } + + /* reset the sender */ + checklist->sender = NULL; + + endpoint_pair_t *pair; + if (get_triggered_pair(checklist, &pair) != SUCCESS) + { + DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check"); + + if (checklist->pairs->find_first(checklist->pairs, + (linked_list_match_t)match_waiting_pair, + (void**)&pair) != SUCCESS) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_IKE, "no pairs in waiting state, aborting"); + return JOB_REQUEUE_NONE; + } + } + else + { + DBG1(DBG_IKE, "triggered check found"); + } + + check_t *check = check_create(); + check->mid = pair->id; + check->src = pair->local->clone(pair->local); + check->dst = pair->remote->clone(pair->remote); + check->connect_id = chunk_clone(checklist->connect_id); + check->endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, NULL, + NULL); + + pair->state = CHECK_IN_PROGRESS; + + send_check(this, checklist, check, pair, TRUE); + + check_destroy(check); + + /* schedule this job again */ + schedule_checks(this, checklist, ME_INTERVAL); + + this->mutex->unlock(this->mutex); + + /* we reschedule it manually */ + return JOB_REQUEUE_NONE; +} + +/** + * Schedules checks for a checklist (time in ms) + */ +static void schedule_checks(private_connect_manager_t *this, + check_list_t *checklist, u_int32_t time) +{ + callback_data_t *data = callback_data_create(this, checklist->connect_id); + checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, + data, (callback_job_cleanup_t)callback_data_destroy, NULL); + lib->scheduler->schedule_job_ms(lib->scheduler, checklist->sender, time); +} + +/** + * Initiates waiting mediated connections + */ +static job_requeue_t initiate_mediated(initiate_data_t *data) +{ + check_list_t *checklist = data->checklist; + initiated_t *initiated = data->initiated; + + endpoint_pair_t *pair; + if (get_best_valid_pair(checklist, &pair) == SUCCESS) + { + ike_sa_id_t *waiting_sa; + enumerator_t *enumerator = initiated->mediated->create_enumerator( + initiated->mediated); + while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) + { + ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa); + if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS) + { + DBG1(DBG_IKE, "establishing mediated connection failed"); + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); + } + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); + } + } + enumerator->destroy(enumerator); + } + else + { + /* this should (can?) not happen */ + } + + return JOB_REQUEUE_NONE; +} + +/** + * Finishes checks for a checklist + */ +static void finish_checks(private_connect_manager_t *this, check_list_t *checklist) +{ + if (checklist->is_initiator) + { + initiated_t *initiated; + if (get_initiated_by_ids(this, checklist->initiator.id, + checklist->responder.id, &initiated) == SUCCESS) + { + callback_job_t *job; + + remove_checklist(this, checklist); + remove_initiated(this, initiated); + + initiate_data_t *data = initiate_data_create(checklist, initiated); + job = callback_job_create((callback_job_cb_t)initiate_mediated, + data, (callback_job_cleanup_t)initiate_data_destroy, NULL); + lib->processor->queue_job(lib->processor, (job_t*)job); + return; + } + else + { + DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y'" + " and '%Y'", checklist->initiator.id, checklist->responder.id); + } + } +} + +/** + * Process the response to one of our requests + */ +static void process_response(private_connect_manager_t *this, check_t *check, + check_list_t *checklist) +{ + endpoint_pair_t *pair; + if (get_pair_by_id(checklist, check->mid, &pair) == SUCCESS) + { + if (pair->local->equals(pair->local, check->dst) && + pair->remote->equals(pair->remote, check->src)) + { + DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", + pair->id, pair->local, pair->remote); + pair->state = CHECK_SUCCEEDED; + } + + linked_list_t *local_endpoints = checklist->is_initiator ? + checklist->initiator.endpoints : checklist->responder.endpoints; + + endpoint_notify_t *local_endpoint; + if (endpoints_contain(local_endpoints, + check->endpoint->get_host(check->endpoint), + &local_endpoint) != SUCCESS) + { + local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, + check->endpoint->get_host(check->endpoint), pair->local); + local_endpoint->set_priority(local_endpoint, + check->endpoint->get_priority(check->endpoint)); + local_endpoints->insert_last(local_endpoints, local_endpoint); + } + + update_checklist_state(this, checklist); + + switch(checklist->state) + { + case CHECK_SUCCEEDED: + case CHECK_FAILED: + finish_checks(this, checklist); + break; + default: + break; + } + } + else + { + DBG1(DBG_IKE, "pair with id '%d' not found", check->mid); + } +} + +static void process_request(private_connect_manager_t *this, check_t *check, + check_list_t *checklist) +{ + linked_list_t *remote_endpoints = checklist->is_initiator ? + checklist->responder.endpoints : checklist->initiator.endpoints; + + endpoint_notify_t *peer_reflexive, *remote_endpoint; + peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, + check->src, NULL); + peer_reflexive->set_priority(peer_reflexive, + check->endpoint->get_priority(check->endpoint)); + + if (endpoints_contain(remote_endpoints, check->src, &remote_endpoint) != SUCCESS) + { + remote_endpoint = peer_reflexive->clone(peer_reflexive); + remote_endpoints->insert_last(remote_endpoints, remote_endpoint); + } + + endpoint_pair_t *pair; + if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, + &pair) == SUCCESS) + { + switch(pair->state) + { + case CHECK_IN_PROGRESS: + /* prevent retransmissions */ + pair->retransmitted = ME_MAX_RETRANS; + /* FIXME: we should wait to the next rto to send the triggered + * check */ + /* fall-through */ + case CHECK_WAITING: + case CHECK_FAILED: + queue_triggered_check(this, checklist, pair); + break; + case CHECK_SUCCEEDED: + default: + break; + } + } + else + { + endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL); + + endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint; + endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint; + + pair = endpoint_pair_create(initiator, responder, checklist->is_initiator); + pair->id = checklist->pairs->get_count(checklist->pairs) + 1; + + insert_pair_by_priority(checklist->pairs, pair); + + queue_triggered_check(this, checklist, pair); + + local_endpoint->destroy(local_endpoint); + } + + check_t *response = check_create(); + + response->mid = check->mid; + response->src = check->dst->clone(check->dst); + response->dst = check->src->clone(check->src); + response->connect_id = chunk_clone(check->connect_id); + response->endpoint = peer_reflexive; + + send_check(this, checklist, response, pair, FALSE); + + check_destroy(response); +} + +METHOD(connect_manager_t, process_check, void, + private_connect_manager_t *this, message_t *message) +{ + if (message->parse_body(message, NULL) != SUCCESS) + { + DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + exchange_type_names, message->get_exchange_type(message), + message->get_request(message) ? "request" : "response", + message->get_message_id(message)); + return; + } + + check_t *check = check_create(); + check->mid = message->get_message_id(message); + check->src = message->get_source(message); + check->src = check->src->clone(check->src); + check->dst = message->get_destination(message); + check->dst = check->dst->clone(check->dst); + + if (process_payloads(message, check) != SUCCESS) + { + DBG1(DBG_IKE, "invalid connectivity check %s received", + message->get_request(message) ? "request" : "response"); + check_destroy(check); + return; + } + + this->mutex->lock(this->mutex); + + check_list_t *checklist; + if (get_checklist_by_id(this, check->connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found", + &check->connect_id); + check_destroy(check); + this->mutex->unlock(this->mutex); + return; + } + + chunk_t sig = build_signature(this, checklist, check, FALSE); + if (!chunk_equals(sig, check->auth)) + { + DBG1(DBG_IKE, "connectivity check verification failed"); + check_destroy(check); + chunk_free(&sig); + this->mutex->unlock(this->mutex); + return; + } + chunk_free(&sig); + + if (message->get_request(message)) + { + process_request(this, check, checklist); + } + else + { + process_response(this, check, checklist); + } + + this->mutex->unlock(this->mutex); + + check_destroy(check); +} + +METHOD(connect_manager_t, check_and_register, bool, + private_connect_manager_t *this, identification_t *id, + identification_t *peer_id, ike_sa_id_t *mediated_sa) +{ + initiated_t *initiated; + bool already_there = TRUE; + + this->mutex->lock(this->mutex); + + if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) + { + DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", + peer_id); + initiated = initiated_create(id, peer_id); + this->initiated->insert_last(this->initiated, initiated); + already_there = FALSE; + } + + if (initiated->mediated->find_first(initiated->mediated, + (linked_list_match_t)mediated_sa->equals, + NULL, mediated_sa) != SUCCESS) + { + initiated->mediated->insert_last(initiated->mediated, + mediated_sa->clone(mediated_sa)); + } + + this->mutex->unlock(this->mutex); + + return already_there; +} + +METHOD(connect_manager_t, check_and_initiate, void, + private_connect_manager_t *this, ike_sa_id_t *mediation_sa, + identification_t *id, identification_t *peer_id) +{ + initiated_t *initiated; + + this->mutex->lock(this->mutex); + + if (get_initiated_by_ids(this, id, peer_id, &initiated) != SUCCESS) + { + DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id); + this->mutex->unlock(this->mutex); + return; + } + + ike_sa_id_t *waiting_sa; + enumerator_t *enumerator = initiated->mediated->create_enumerator( + initiated->mediated); + while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) + { + job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, + waiting_sa); + lib->processor->queue_job(lib->processor, job); + } + enumerator->destroy(enumerator); + + this->mutex->unlock(this->mutex); +} + +METHOD(connect_manager_t, set_initiator_data, status_t, + private_connect_manager_t *this, identification_t *initiator, + identification_t *responder, chunk_t connect_id, chunk_t key, + linked_list_t *endpoints, bool is_initiator) +{ + check_list_t *checklist; + + this->mutex->lock(this->mutex); + + if (get_checklist_by_id(this, connect_id, NULL) == SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", + &connect_id); + this->mutex->unlock(this->mutex); + return FAILED; + } + + checklist = check_list_create(initiator, responder, connect_id, key, + endpoints, is_initiator); + this->checklists->insert_last(this->checklists, checklist); + + this->mutex->unlock(this->mutex); + + return SUCCESS; +} + +METHOD(connect_manager_t, set_responder_data, status_t, + private_connect_manager_t *this, chunk_t connect_id, chunk_t key, + linked_list_t *endpoints) +{ + check_list_t *checklist; + + this->mutex->lock(this->mutex); + + if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found", + &connect_id); + this->mutex->unlock(this->mutex); + return NOT_FOUND; + } + + checklist->responder.key = chunk_clone(key); + checklist->responder.endpoints = endpoints->clone_offset(endpoints, + offsetof(endpoint_notify_t, clone)); + checklist->state = CHECK_WAITING; + + build_pairs(checklist); + + /* send the first check immediately */ + schedule_checks(this, checklist, 0); + + this->mutex->unlock(this->mutex); + + return SUCCESS; +} + +METHOD(connect_manager_t, stop_checks, status_t, + private_connect_manager_t *this, chunk_t connect_id) +{ + check_list_t *checklist; + + this->mutex->lock(this->mutex); + + if (get_checklist_by_id(this, connect_id, &checklist) != SUCCESS) + { + DBG1(DBG_IKE, "checklist with id '%#B' not found", + &connect_id); + this->mutex->unlock(this->mutex); + return NOT_FOUND; + } + + DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id); + + remove_checklist(this, checklist); + check_list_destroy(checklist); + + this->mutex->unlock(this->mutex); + + return SUCCESS; +} + +METHOD(connect_manager_t, destroy, void, + private_connect_manager_t *this) +{ + this->mutex->lock(this->mutex); + + this->checklists->destroy_function(this->checklists, + (void*)check_list_destroy); + this->initiated->destroy_function(this->initiated, + (void*)initiated_destroy); + DESTROY_IF(this->hasher); + + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * Described in header. + */ +connect_manager_t *connect_manager_create() +{ + private_connect_manager_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + .check_and_register = _check_and_register, + .check_and_initiate = _check_and_initiate, + .set_initiator_data = _set_initiator_data, + .set_responder_data = _set_responder_data, + .process_check = _process_check, + .stop_checks = _stop_checks, + }, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .checklists = linked_list_create(), + .initiated = linked_list_create(), + ); + + if (this->hasher == NULL) + { + DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported"); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/connect_manager.h b/src/libcharon/sa/ikev2/connect_manager.h new file mode 100644 index 000000000..e667e1f70 --- /dev/null +++ b/src/libcharon/sa/ikev2/connect_manager.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2007-2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup connect_manager connect_manager + * @{ @ingroup ikev2 + */ + +#ifndef CONNECT_MANAGER_H_ +#define CONNECT_MANAGER_H_ + +typedef struct connect_manager_t connect_manager_t; + +#include +#include +#include + +/** + * The connection manager is responsible for establishing a direct + * connection with another peer. + */ +struct connect_manager_t { + + /** + * Checks if a there is already a mediated connection registered + * between two peers. + * + * @param id my id + * @param peer_id the other peer's id + * @param mediated_sa the IKE_SA ID of the mediated connection + * @returns + * - TRUE, if a mediated connection is registered + * - FALSE, otherwise + */ + bool (*check_and_register) (connect_manager_t *this, identification_t *id, + identification_t *peer_id, + ike_sa_id_t *mediated_sa); + + /** + * Checks if there are waiting connections with a specific peer. + * If so, reinitiate them. + * + * @param id my id + * @param peer_id the other peer's id + */ + void (*check_and_initiate) (connect_manager_t *this, + ike_sa_id_t *mediation_sa, identification_t *id, + identification_t *peer_id); + + /** + * Creates a checklist and sets the initiator's data. + * + * @param initiator ID of the initiator + * @param responder ID of the responder + * @param connect_id the connect ID provided by the initiator + * @param key the initiator's key + * @param endpoints the initiator's endpoints + * @param is_initiator TRUE, if the caller of this method is the initiator + * @returns SUCCESS + */ + status_t (*set_initiator_data) (connect_manager_t *this, + identification_t *initiator, + identification_t *responder, + chunk_t connect_id, chunk_t key, + linked_list_t *endpoints, + bool is_initiator); + + /** + * Updates a checklist and sets the responder's data. The checklist's + * state is advanced to WAITING which means that checks will be sent. + * + * @param connect_id the connect ID + * @param chunk_t the responder's key + * @param endpoints the responder's endpoints + * @returns + * - NOT_FOUND, if the checklist has not been found + * - SUCCESS, otherwise + */ + status_t (*set_responder_data) (connect_manager_t *this, + chunk_t connect_id, chunk_t key, + linked_list_t *endpoints); + + /** + * Stops checks for a checklist. Called after the responder received an + * IKE_SA_INIT request which contains a ME_CONNECTID payload. + * + * @param connect_id the connect ID + * @returns + * - NOT_FOUND, if the checklist has not been found + * - SUCCESS, otherwise + */ + status_t (*stop_checks) (connect_manager_t *this, chunk_t connect_id); + + /** + * Processes a connectivity check + * + * @param message the received message + */ + void (*process_check) (connect_manager_t *this, message_t *message); + + /** + * Destroys the manager with all data. + */ + void (*destroy) (connect_manager_t *this); +}; + +/** + * Create a manager. + * + * @returns connect_manager_t object + */ +connect_manager_t *connect_manager_create(void); + +#endif /** CONNECT_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c new file mode 100644 index 000000000..4d0683f0a --- /dev/null +++ b/src/libcharon/sa/ikev2/keymat_v2.c @@ -0,0 +1,687 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "keymat_v2.h" + +#include +#include + +typedef struct private_keymat_v2_t private_keymat_v2_t; + +/** + * Private data of an keymat_t object. + */ +struct private_keymat_v2_t { + + /** + * Public keymat_v2_t interface. + */ + keymat_v2_t public; + + /** + * IKE_SA Role, initiator or responder + */ + bool initiator; + + /** + * inbound AEAD + */ + aead_t *aead_in; + + /** + * outbound AEAD + */ + aead_t *aead_out; + + /** + * General purpose PRF + */ + prf_t *prf; + + /** + * Negotiated PRF algorithm + */ + pseudo_random_function_t prf_alg; + + /** + * Key to derive key material from for CHILD_SAs, rekeying + */ + chunk_t skd; + + /** + * Key to build outging authentication data (SKp) + */ + chunk_t skp_build; + + /** + * Key to verify incoming authentication data (SKp) + */ + chunk_t skp_verify; +}; + +METHOD(keymat_t, get_version, ike_version_t, + private_keymat_v2_t *this) +{ + return IKEV2; +} + +METHOD(keymat_t, create_dh, diffie_hellman_t*, + private_keymat_v2_t *this, diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group); +} + +METHOD(keymat_t, create_nonce_gen, nonce_gen_t*, + private_keymat_v2_t *this) +{ + return lib->crypto->create_nonce_gen(lib->crypto); +} + +/** + * Derive IKE keys for a combined AEAD algorithm + */ +static bool derive_ike_aead(private_keymat_v2_t *this, u_int16_t alg, + u_int16_t key_size, prf_plus_t *prf_plus) +{ + aead_t *aead_i, *aead_r; + chunk_t key = chunk_empty; + + /* SK_ei/SK_er used for encryption */ + aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); + aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); + if (aead_i == NULL || aead_r == NULL) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, alg, key_size); + goto failure; + } + key_size = aead_i->get_key_size(aead_i); + if (key_size != aead_r->get_key_size(aead_r)) + { + goto failure; + } + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_ei secret %B", &key); + if (!aead_i->set_key(aead_i, key)) + { + goto failure; + } + chunk_clear(&key); + + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_er secret %B", &key); + if (!aead_r->set_key(aead_r, key)) + { + goto failure; + } + + if (this->initiator) + { + this->aead_in = aead_r; + this->aead_out = aead_i; + } + else + { + this->aead_in = aead_i; + this->aead_out = aead_r; + } + aead_i = aead_r = NULL; + +failure: + DESTROY_IF(aead_i); + DESTROY_IF(aead_r); + chunk_clear(&key); + return this->aead_in && this->aead_out; +} + +/** + * Derive IKE keys for traditional encryption and MAC algorithms + */ +static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg, + u_int16_t enc_size, u_int16_t int_alg, prf_plus_t *prf_plus) +{ + crypter_t *crypter_i = NULL, *crypter_r = NULL; + signer_t *signer_i, *signer_r; + size_t key_size; + chunk_t key = chunk_empty; + + signer_i = lib->crypto->create_signer(lib->crypto, int_alg); + signer_r = lib->crypto->create_signer(lib->crypto, int_alg); + crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); + crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); + if (signer_i == NULL || signer_r == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, INTEGRITY_ALGORITHM, + integrity_algorithm_names, int_alg); + goto failure; + } + if (crypter_i == NULL || crypter_r == NULL) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, enc_alg, enc_size); + goto failure; + } + + /* SK_ai/SK_ar used for integrity protection */ + key_size = signer_i->get_key_size(signer_i); + + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_ai secret %B", &key); + if (!signer_i->set_key(signer_i, key)) + { + goto failure; + } + chunk_clear(&key); + + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_ar secret %B", &key); + if (!signer_r->set_key(signer_r, key)) + { + goto failure; + } + chunk_clear(&key); + + /* SK_ei/SK_er used for encryption */ + key_size = crypter_i->get_key_size(crypter_i); + + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_ei secret %B", &key); + if (!crypter_i->set_key(crypter_i, key)) + { + goto failure; + } + chunk_clear(&key); + + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_er secret %B", &key); + if (!crypter_r->set_key(crypter_r, key)) + { + goto failure; + } + + if (this->initiator) + { + this->aead_in = aead_create(crypter_r, signer_r); + this->aead_out = aead_create(crypter_i, signer_i); + } + else + { + this->aead_in = aead_create(crypter_i, signer_i); + this->aead_out = aead_create(crypter_r, signer_r); + } + signer_i = signer_r = NULL; + crypter_i = crypter_r = NULL; + +failure: + chunk_clear(&key); + DESTROY_IF(signer_i); + DESTROY_IF(signer_r); + DESTROY_IF(crypter_i); + DESTROY_IF(crypter_r); + return this->aead_in && this->aead_out; +} + +METHOD(keymat_v2_t, derive_ike_keys, bool, + private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, chunk_t rekey_skd) +{ + chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed; + chunk_t spi_i, spi_r; + prf_plus_t *prf_plus = NULL; + u_int16_t alg, key_size, int_alg; + prf_t *rekey_prf = NULL; + + spi_i = chunk_alloca(sizeof(u_int64_t)); + spi_r = chunk_alloca(sizeof(u_int64_t)); + + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + + /* Create SAs general purpose PRF first, we may use it here */ + if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, PSEUDO_RANDOM_FUNCTION); + return FALSE; + } + this->prf_alg = alg; + this->prf = lib->crypto->create_prf(lib->crypto, alg); + if (this->prf == NULL) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret); + /* full nonce is used as seed for PRF+ ... */ + full_nonce = chunk_cat("cc", nonce_i, nonce_r); + /* but the PRF may need a fixed key which only uses the first bytes of + * the nonces. */ + switch (alg) + { + case PRF_AES128_XCBC: + /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does + * not and therefore fixed key semantics apply to XCBC for key + * derivation. */ + case PRF_CAMELLIA128_XCBC: + /* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we + * assume fixed key length. */ + key_size = this->prf->get_key_size(this->prf)/2; + nonce_i.len = min(nonce_i.len, key_size); + nonce_r.len = min(nonce_r.len, key_size); + break; + default: + /* all other algorithms use variable key length, full nonce */ + break; + } + fixed_nonce = chunk_cat("cc", nonce_i, nonce_r); + *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id); + *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id); + prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r); + + /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) + * + * if we are rekeying, SKEYSEED is built on another way + */ + if (rekey_function == PRF_UNDEFINED) /* not rekeying */ + { + /* SKEYSEED = prf(Ni | Nr, g^ir) */ + if (this->prf->set_key(this->prf, fixed_nonce) && + this->prf->allocate_bytes(this->prf, secret, &skeyseed) && + this->prf->set_key(this->prf, skeyseed)) + { + prf_plus = prf_plus_create(this->prf, TRUE, prf_plus_seed); + } + } + else + { + /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) + * use OLD SAs PRF functions for both prf_plus and prf */ + rekey_prf = lib->crypto->create_prf(lib->crypto, rekey_function); + if (!rekey_prf) + { + DBG1(DBG_IKE, "PRF of old SA %N not supported!", + pseudo_random_function_names, rekey_function); + chunk_free(&full_nonce); + chunk_free(&fixed_nonce); + chunk_clear(&prf_plus_seed); + return FALSE; + } + secret = chunk_cat("mc", secret, full_nonce); + if (rekey_prf->set_key(rekey_prf, rekey_skd) && + rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed) && + rekey_prf->set_key(rekey_prf, skeyseed)) + { + prf_plus = prf_plus_create(rekey_prf, TRUE, prf_plus_seed); + } + } + DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); + + chunk_clear(&skeyseed); + chunk_clear(&secret); + chunk_free(&full_nonce); + chunk_free(&fixed_nonce); + chunk_clear(&prf_plus_seed); + + if (!prf_plus) + { + goto failure; + } + + /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ + + /* SK_d is used for generating CHILD_SA key mat => store for later use */ + key_size = this->prf->get_key_size(this->prf); + if (!prf_plus->allocate_bytes(prf_plus, key_size, &this->skd)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_d secret %B", &this->skd); + + if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, ENCRYPTION_ALGORITHM); + goto failure; + } + + if (encryption_algorithm_is_aead(alg)) + { + if (!derive_ike_aead(this, alg, key_size, prf_plus)) + { + goto failure; + } + } + else + { + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, NULL)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, INTEGRITY_ALGORITHM); + goto failure; + } + if (!derive_ike_traditional(this, alg, key_size, int_alg, prf_plus)) + { + goto failure; + } + } + + /* SK_pi/SK_pr used for authentication => stored for later */ + key_size = this->prf->get_key_size(this->prf); + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_pi secret %B", &key); + if (this->initiator) + { + this->skp_build = key; + } + else + { + this->skp_verify = key; + } + if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + { + goto failure; + } + DBG4(DBG_IKE, "Sk_pr secret %B", &key); + if (this->initiator) + { + this->skp_verify = key; + } + else + { + this->skp_build = key; + } + + /* all done, prf_plus not needed anymore */ +failure: + DESTROY_IF(prf_plus); + DESTROY_IF(rekey_prf); + + return this->skp_build.len && this->skp_verify.len; +} + +METHOD(keymat_v2_t, derive_child_keys, bool, + private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) +{ + u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; + chunk_t seed, secret = chunk_empty; + prf_plus_t *prf_plus; + + if (dh) + { + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_CHD, "DH secret %B", &secret); + } + seed = chunk_cata("mcc", secret, nonce_i, nonce_r); + DBG4(DBG_CHD, "seed %B", &seed); + + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &enc_alg, &enc_size)) + { + DBG2(DBG_CHD, " using %N for encryption", + encryption_algorithm_names, enc_alg); + + if (!enc_size) + { + enc_size = keymat_get_keylen_encr(enc_alg); + } + if (enc_alg != ENCR_NULL && !enc_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + encryption_algorithm_names, enc_alg); + return FALSE; + } + /* to bytes */ + enc_size /= 8; + + /* CCM/GCM/CTR/GMAC needs additional bytes */ + switch (enc_alg) + { + case ENCR_AES_CCM_ICV8: + case ENCR_AES_CCM_ICV12: + case ENCR_AES_CCM_ICV16: + case ENCR_CAMELLIA_CCM_ICV8: + case ENCR_CAMELLIA_CCM_ICV12: + case ENCR_CAMELLIA_CCM_ICV16: + enc_size += 3; + break; + case ENCR_AES_GCM_ICV8: + case ENCR_AES_GCM_ICV12: + case ENCR_AES_GCM_ICV16: + case ENCR_AES_CTR: + case ENCR_NULL_AUTH_AES_GMAC: + enc_size += 4; + break; + default: + break; + } + } + + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, &int_size)) + { + DBG2(DBG_CHD, " using %N for integrity", + integrity_algorithm_names, int_alg); + + if (!int_size) + { + int_size = keymat_get_keylen_integ(int_alg); + } + if (!int_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + integrity_algorithm_names, int_alg); + return FALSE; + } + /* to bytes */ + int_size /= 8; + } + + if (!this->prf->set_key(this->prf, this->skd)) + { + return FALSE; + } + prf_plus = prf_plus_create(this->prf, TRUE, seed); + if (!prf_plus) + { + return FALSE; + } + + *encr_i = *integ_i = *encr_r = *integ_r = chunk_empty; + if (!prf_plus->allocate_bytes(prf_plus, enc_size, encr_i) || + !prf_plus->allocate_bytes(prf_plus, int_size, integ_i) || + !prf_plus->allocate_bytes(prf_plus, enc_size, encr_r) || + !prf_plus->allocate_bytes(prf_plus, int_size, integ_r)) + { + chunk_free(encr_i); + chunk_free(integ_i); + chunk_free(encr_r); + chunk_free(integ_r); + prf_plus->destroy(prf_plus); + return FALSE; + } + + prf_plus->destroy(prf_plus); + + if (enc_size) + { + DBG4(DBG_CHD, "encryption initiator key %B", encr_i); + DBG4(DBG_CHD, "encryption responder key %B", encr_r); + } + if (int_size) + { + DBG4(DBG_CHD, "integrity initiator key %B", integ_i); + DBG4(DBG_CHD, "integrity responder key %B", integ_r); + } + return TRUE; +} + +METHOD(keymat_v2_t, get_skd, pseudo_random_function_t, + private_keymat_v2_t *this, chunk_t *skd) +{ + *skd = this->skd; + return this->prf_alg; +} + +METHOD(keymat_t, get_aead, aead_t*, + private_keymat_v2_t *this, bool in) +{ + return in ? this->aead_in : this->aead_out; +} + +METHOD(keymat_v2_t, get_auth_octets, bool, + private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id, char reserved[3], chunk_t *octets) +{ + chunk_t chunk, idx; + chunk_t skp; + + skp = verify ? this->skp_verify : this->skp_build; + + chunk = chunk_alloca(4); + chunk.ptr[0] = id->get_type(id); + memcpy(chunk.ptr + 1, reserved, 3); + idx = chunk_cata("cc", chunk, id->get_encoding(id)); + + DBG3(DBG_IKE, "IDx' %B", &idx); + DBG3(DBG_IKE, "SK_p %B", &skp); + if (!this->prf->set_key(this->prf, skp) || + !this->prf->allocate_bytes(this->prf, idx, &chunk)) + { + return FALSE; + } + *octets = chunk_cat("ccm", ike_sa_init, nonce, chunk); + DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", octets); + return TRUE; +} + +/** + * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. + */ +#define IKEV2_KEY_PAD "Key Pad for IKEv2" +#define IKEV2_KEY_PAD_LENGTH 17 + +METHOD(keymat_v2_t, get_psk_sig, bool, + private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, + chunk_t secret, identification_t *id, char reserved[3], chunk_t *sig) +{ + chunk_t key_pad, key, octets; + + if (!secret.len) + { /* EAP uses SK_p if no MSK has been established */ + secret = verify ? this->skp_verify : this->skp_build; + } + if (!get_auth_octets(this, verify, ike_sa_init, nonce, id, reserved, &octets)) + { + return FALSE; + } + /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), ) */ + key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH); + if (!this->prf->set_key(this->prf, secret) || + !this->prf->allocate_bytes(this->prf, key_pad, &key)) + { + chunk_free(&octets); + return FALSE; + } + if (!this->prf->set_key(this->prf, key) || + !this->prf->allocate_bytes(this->prf, octets, sig)) + { + chunk_free(&key); + chunk_free(&octets); + return FALSE; + } + DBG4(DBG_IKE, "secret %B", &secret); + DBG4(DBG_IKE, "prf(secret, keypad) %B", &key); + DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", sig); + chunk_free(&octets); + chunk_free(&key); + + return TRUE; +} + +METHOD(keymat_t, destroy, void, + private_keymat_v2_t *this) +{ + DESTROY_IF(this->aead_in); + DESTROY_IF(this->aead_out); + DESTROY_IF(this->prf); + chunk_clear(&this->skd); + chunk_clear(&this->skp_verify); + chunk_clear(&this->skp_build); + free(this); +} + +/** + * See header + */ +keymat_v2_t *keymat_v2_create(bool initiator) +{ + private_keymat_v2_t *this; + + INIT(this, + .public = { + .keymat = { + .get_version = _get_version, + .create_dh = _create_dh, + .create_nonce_gen = _create_nonce_gen, + .get_aead = _get_aead, + .destroy = _destroy, + }, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, + }, + .initiator = initiator, + .prf_alg = PRF_UNDEFINED, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h new file mode 100644 index 000000000..04432f05b --- /dev/null +++ b/src/libcharon/sa/ikev2/keymat_v2.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup keymat_v2 keymat_v2 + * @{ @ingroup ikev2 + */ + +#ifndef KEYMAT_V2_H_ +#define KEYMAT_V2_H_ + +#include + +typedef struct keymat_v2_t keymat_v2_t; + +/** + * Derivation and management of sensitive keying material, IKEv2 variant. + */ +struct keymat_v2_t { + + /** + * Implements keymat_t. + */ + keymat_t keymat; + + /** + * Derive keys for the IKE_SA. + * + * These keys are not handed out, but are used by the associated signers, + * crypters and authentication functions. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh() + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param id IKE_SA identifier + * @param rekey_prf PRF of old SA if rekeying, PRF_UNDEFINED otherwise + * @param rekey_sdk SKd of old SA if rekeying + * @return TRUE on success + */ + bool (*derive_ike_keys)(keymat_v2_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t nonce_i, + chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, + chunk_t rekey_skd); + + /** + * Derive keys for a CHILD_SA. + * + * The keys for the CHILD_SA are allocated in the integ and encr chunks. + * An implementation might hand out encrypted keys only, which are + * decrypted in the kernel before use. + * If no PFS is used for the CHILD_SA, dh can be NULL. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh(), or NULL + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param encr_i chunk to write initiators encryption key to + * @param integ_i chunk to write initiators integrity key to + * @param encr_r chunk to write responders encryption key to + * @param integ_r chunk to write responders integrity key to + * @return TRUE on success + */ + bool (*derive_child_keys)(keymat_v2_t *this, + proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r); + /** + * Get SKd to pass to derive_ikey_keys() during rekeying. + * + * @param skd chunk to write SKd to (internal data) + * @return PRF function to derive keymat + */ + pseudo_random_function_t (*get_skd)(keymat_v2_t *this, chunk_t *skd); + + /** + * Generate octets to use for authentication procedure (RFC4306 2.15). + * + * This method creates the plain octets and is usually signed by a private + * key. PSK and EAP authentication include a secret into the data, use + * the get_psk_sig() method instead. + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param id identity + * @param reserved reserved bytes of id_payload + * @param octests chunk receiving allocated auth octets + * @return TRUE if octets created successfully + */ + bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id, + char reserved[3], chunk_t *octets); + /** + * Build the shared secret signature used for PSK and EAP authentication. + * + * This method wraps the get_auth_octets() method and additionally + * includes the secret into the signature. If no secret is given, SK_p is + * used as secret (used for EAP methods without MSK). + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param secret optional secret to include into signature + * @param id identity + * @param reserved reserved bytes of id_payload + * @param sign chunk receiving allocated signature octets + * @return TRUE if signature created successfully + */ + bool (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, chunk_t secret, + identification_t *id, char reserved[3], chunk_t *sig); +}; + +/** + * Create a keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +keymat_v2_t *keymat_v2_create(bool initiator); + +#endif /** KEYMAT_V2_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/mediation_manager.c b/src/libcharon/sa/ikev2/mediation_manager.c new file mode 100644 index 000000000..60eeb5d4b --- /dev/null +++ b/src/libcharon/sa/ikev2/mediation_manager.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "mediation_manager.h" + +#include +#include +#include +#include + +typedef struct peer_t peer_t; + +/** + * An entry in the linked list. + */ +struct peer_t { + /** id of the peer */ + identification_t *id; + + /** sa id of the peer, NULL if offline */ + ike_sa_id_t *ike_sa_id; + + /** list of peer ids that reuested this peer */ + linked_list_t *requested_by; +}; + +/** + * Implementation of peer_t.destroy. + */ +static void peer_destroy(peer_t *this) +{ + DESTROY_IF(this->id); + DESTROY_IF(this->ike_sa_id); + this->requested_by->destroy_offset(this->requested_by, + offsetof(identification_t, destroy)); + free(this); +} + +/** + * Creates a new entry for the list. + */ +static peer_t *peer_create(identification_t *id, ike_sa_id_t* ike_sa_id) +{ + peer_t *this; + INIT(this, + .id = id->clone(id), + .ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL, + .requested_by = linked_list_create(), + ); + return this; +} + +typedef struct private_mediation_manager_t private_mediation_manager_t; + +/** + * Additional private members of mediation_manager_t. + */ +struct private_mediation_manager_t { + /** + * Public interface of mediation_manager_t. + */ + mediation_manager_t public; + + /** + * Lock for exclusivly accessing the manager. + */ + mutex_t *mutex; + + /** + * Linked list with state entries. + */ + linked_list_t *peers; +}; + +/** + * Registers a peer's ID at another peer, if it is not yet registered + */ +static void register_peer(peer_t *peer, identification_t *peer_id) +{ + enumerator_t *enumerator; + identification_t *current; + + enumerator = peer->requested_by->create_enumerator(peer->requested_by); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (peer_id->equals(peer_id, current)) + { + enumerator->destroy(enumerator); + return; + } + } + enumerator->destroy(enumerator); + + peer->requested_by->insert_last(peer->requested_by, + peer_id->clone(peer_id)); +} + +/** + * Get a peer_t object by a peer's id + */ +static status_t get_peer_by_id(private_mediation_manager_t *this, + identification_t *id, peer_t **peer) +{ + enumerator_t *enumerator; + peer_t *current; + status_t status = NOT_FOUND; + + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (id->equals(id, current->id)) + { + if (peer) + { + *peer = current; + } + status = SUCCESS; + break; + } + } + enumerator->destroy(enumerator); + + return status; +} + +/** + * Check if a given peer is registered at other peers. If so, remove it there + * and then remove peers completely that are not online and have no registered + * peers. + */ +static void unregister_peer(private_mediation_manager_t *this, + identification_t *peer_id) +{ + enumerator_t *enumerator, *enumerator_r; + peer_t *peer; + identification_t *registered; + + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + enumerator_r = peer->requested_by->create_enumerator(peer->requested_by); + while (enumerator_r->enumerate(enumerator_r, (void**)®istered)) + { + if (peer_id->equals(peer_id, registered)) + { + peer->requested_by->remove_at(peer->requested_by, enumerator_r); + registered->destroy(registered); + break; + } + } + enumerator_r->destroy(enumerator_r); + + if (!peer->ike_sa_id && + !peer->requested_by->get_count(peer->requested_by)) + { + this->peers->remove_at(this->peers, enumerator); + peer_destroy(peer); + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(mediation_manager_t, remove_sa, void, + private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) +{ + enumerator_t *enumerator; + peer_t *peer; + + this->mutex->lock(this->mutex); + + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + if (ike_sa_id->equals(ike_sa_id, peer->ike_sa_id)) + { + this->peers->remove_at(this->peers, enumerator); + + unregister_peer(this, peer->id); + + peer_destroy(peer); + break; + } + } + enumerator->destroy(enumerator); + + this->mutex->unlock(this->mutex); +} + +METHOD(mediation_manager_t, update_sa_id, void, + private_mediation_manager_t *this, identification_t *peer_id, + ike_sa_id_t *ike_sa_id) +{ + enumerator_t *enumerator; + peer_t *peer; + bool found = FALSE; + + this->mutex->lock(this->mutex); + + enumerator = this->peers->create_enumerator(this->peers); + while (enumerator->enumerate(enumerator, (void**)&peer)) + { + if (peer_id->equals(peer_id, peer->id)) + { + DESTROY_IF(peer->ike_sa_id); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + DBG2(DBG_IKE, "adding peer '%Y'", peer_id); + peer = peer_create(peer_id, NULL); + this->peers->insert_last(this->peers, peer); + } + + DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%Y'", peer_id); + peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL; + + /* send callbacks to registered peers */ + identification_t *requester; + while(peer->requested_by->remove_last(peer->requested_by, + (void**)&requester) == SUCCESS) + { + job_t *job = (job_t*)mediation_callback_job_create(requester, peer_id); + lib->processor->queue_job(lib->processor, job); + requester->destroy(requester); + } + + this->mutex->unlock(this->mutex); +} + +METHOD(mediation_manager_t, check, ike_sa_id_t*, + private_mediation_manager_t *this, identification_t *peer_id) +{ + peer_t *peer; + ike_sa_id_t *ike_sa_id; + + this->mutex->lock(this->mutex); + + if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) + { + this->mutex->unlock(this->mutex); + return NULL; + } + + ike_sa_id = peer->ike_sa_id; + + this->mutex->unlock(this->mutex); + + return ike_sa_id; +} + +METHOD(mediation_manager_t, check_and_register, ike_sa_id_t*, + private_mediation_manager_t *this, identification_t *peer_id, + identification_t *requester) +{ + peer_t *peer; + ike_sa_id_t *ike_sa_id; + + this->mutex->lock(this->mutex); + + if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) + { + DBG2(DBG_IKE, "adding peer %Y", peer_id); + peer = peer_create(peer_id, NULL); + this->peers->insert_last(this->peers, peer); + } + + if (!peer->ike_sa_id) + { + /* the peer is not online */ + DBG2(DBG_IKE, "requested peer '%Y' is offline, registering peer '%Y'", + peer_id, requester); + register_peer(peer, requester); + this->mutex->unlock(this->mutex); + return NULL; + } + + ike_sa_id = peer->ike_sa_id; + + this->mutex->unlock(this->mutex); + + return ike_sa_id; +} + +METHOD(mediation_manager_t, destroy, void, + private_mediation_manager_t *this) +{ + this->mutex->lock(this->mutex); + + this->peers->destroy_function(this->peers, (void*)peer_destroy); + + this->mutex->unlock(this->mutex); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * Described in header. + */ +mediation_manager_t *mediation_manager_create() +{ + private_mediation_manager_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + .remove = _remove_sa, + .update_sa_id = _update_sa_id, + .check = _check, + .check_and_register = _check_and_register, + }, + .peers = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + ); + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/mediation_manager.h b/src/libcharon/sa/ikev2/mediation_manager.h new file mode 100644 index 000000000..5212bdb86 --- /dev/null +++ b/src/libcharon/sa/ikev2/mediation_manager.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mediation_manager mediation_manager + * @{ @ingroup ikev2 + */ + +#ifndef MEDIATION_MANAGER_H_ +#define MEDIATION_MANAGER_H_ + +typedef struct mediation_manager_t mediation_manager_t; + +#include +#include + +/** + * The mediation manager is responsible for managing currently online + * peers and registered requests for offline peers on the mediation server. + */ +struct mediation_manager_t { + + /** + * Remove the IKE_SA of a peer. + * + * @param ike_sa_id the IKE_SA ID of the peer's SA + */ + void (*remove) (mediation_manager_t* this, ike_sa_id_t *ike_sa_id); + + /** + * Update the ike_sa_id that is assigned to a peer's ID. If the peer + * is new, it gets a new record assigned. + * + * @param peer_id the peer's ID + * @param ike_sa_id the IKE_SA ID of the peer's SA + */ + void (*update_sa_id) (mediation_manager_t* this, identification_t *peer_id, + ike_sa_id_t *ike_sa_id); + + /** + * Checks if a specific peer is online. + * + * @param peer_id the peer's ID + * @returns + * - IKE_SA ID of the peer's SA. + * - NULL, if the peer is not online. + */ + ike_sa_id_t* (*check) (mediation_manager_t* this, + identification_t *peer_id); + + /** + * Checks if a specific peer is online and registers the requesting + * peer if it is not. + * + * @param peer_id the peer's ID + * @param requester the requesters ID + * @returns + * - IKE_SA ID of the peer's SA. + * - NULL, if the peer is not online. + */ + ike_sa_id_t* (*check_and_register) (mediation_manager_t* this, + identification_t *peer_id, + identification_t *requester); + + /** + * Destroys the manager with all data. + */ + void (*destroy) (mediation_manager_t *this); +}; + +/** + * Create a manager. + * + * @returns mediation_manager_t object + */ +mediation_manager_t *mediation_manager_create(void); + +#endif /** MEDIATION_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c new file mode 100644 index 000000000..53051fab4 --- /dev/null +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -0,0 +1,1502 @@ +/* + * Copyright (C) 2007-2011 Tobias Brunner + * Copyright (C) 2007-2010 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "task_manager_v2.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ME +#include +#endif + +typedef struct exchange_t exchange_t; + +/** + * An exchange in the air, used do detect and handle retransmission + */ +struct exchange_t { + + /** + * Message ID used for this transaction + */ + u_int32_t mid; + + /** + * generated packet for retransmission + */ + packet_t *packet; +}; + +typedef struct private_task_manager_t private_task_manager_t; + +/** + * private data of the task manager + */ +struct private_task_manager_t { + + /** + * public functions + */ + task_manager_v2_t public; + + /** + * associated IKE_SA we are serving + */ + ike_sa_t *ike_sa; + + /** + * Exchange we are currently handling as responder + */ + struct { + /** + * Message ID of the exchange + */ + u_int32_t mid; + + /** + * packet for retransmission + */ + packet_t *packet; + + } responding; + + /** + * Exchange we are currently handling as initiator + */ + struct { + /** + * Message ID of the exchange + */ + u_int32_t mid; + + /** + * how many times we have retransmitted so far + */ + u_int retransmitted; + + /** + * packet for retransmission + */ + packet_t *packet; + + /** + * type of the initated exchange + */ + exchange_type_t type; + + } initiating; + + /** + * List of queued tasks not yet in action + */ + linked_list_t *queued_tasks; + + /** + * List of active tasks, initiated by ourselve + */ + linked_list_t *active_tasks; + + /** + * List of tasks initiated by peer + */ + linked_list_t *passive_tasks; + + /** + * the task manager has been reset + */ + bool reset; + + /** + * Number of times we retransmit messages before giving up + */ + u_int retransmit_tries; + + /** + * Retransmission timeout + */ + double retransmit_timeout; + + /** + * Base to calculate retransmission timeout + */ + double retransmit_base; +}; + +METHOD(task_manager_t, flush_queue, void, + private_task_manager_t *this, task_queue_t queue) +{ + linked_list_t *list; + task_t *task; + + switch (queue) + { + case TASK_QUEUE_ACTIVE: + list = this->active_tasks; + break; + case TASK_QUEUE_PASSIVE: + list = this->passive_tasks; + break; + case TASK_QUEUE_QUEUED: + list = this->queued_tasks; + break; + default: + return; + } + while (list->remove_last(list, (void**)&task) == SUCCESS) + { + task->destroy(task); + } +} + +/** + * flush all tasks in the task manager + */ +static void flush(private_task_manager_t *this) +{ + flush_queue(this, TASK_QUEUE_QUEUED); + flush_queue(this, TASK_QUEUE_PASSIVE); + flush_queue(this, TASK_QUEUE_ACTIVE); +} + +/** + * move a task of a specific type from the queue to the active list + */ +static bool activate_task(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + task_t *task; + bool found = FALSE; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + if (task->get_type(task) == type) + { + DBG2(DBG_IKE, " activating %N task", task_type_names, type); + this->queued_tasks->remove_at(this->queued_tasks, enumerator); + this->active_tasks->insert_last(this->active_tasks, task); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +METHOD(task_manager_t, retransmit, status_t, + private_task_manager_t *this, u_int32_t message_id) +{ + if (this->initiating.packet && message_id == this->initiating.mid) + { + u_int32_t timeout; + job_t *job; + enumerator_t *enumerator; + packet_t *packet; + task_t *task; + ike_mobike_t *mobike = NULL; + + /* check if we are retransmitting a MOBIKE routability check */ + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + if (task->get_type(task) == TASK_IKE_MOBIKE) + { + mobike = (ike_mobike_t*)task; + if (!mobike->is_probing(mobike)) + { + mobike = NULL; + } + break; + } + } + enumerator->destroy(enumerator); + + if (mobike == NULL) + { + if (this->initiating.retransmitted <= this->retransmit_tries) + { + timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 * + pow(this->retransmit_base, this->initiating.retransmitted)); + } + else + { + DBG1(DBG_IKE, "giving up after %d retransmits", + this->initiating.retransmitted - 1); + return DESTROY_ME; + } + + if (this->initiating.retransmitted) + { + DBG1(DBG_IKE, "retransmit %d of request with message ID %d", + this->initiating.retransmitted, message_id); + } + packet = this->initiating.packet->clone(this->initiating.packet); + charon->sender->send(charon->sender, packet); + } + else + { /* for routeability checks, we use a more aggressive behavior */ + if (this->initiating.retransmitted <= ROUTEABILITY_CHECK_TRIES) + { + timeout = ROUTEABILITY_CHECK_INTERVAL; + } + else + { + DBG1(DBG_IKE, "giving up after %d path probings", + this->initiating.retransmitted - 1); + return DESTROY_ME; + } + + if (this->initiating.retransmitted) + { + DBG1(DBG_IKE, "path probing attempt %d", + this->initiating.retransmitted); + } + mobike->transmit(mobike, this->initiating.packet); + } + + this->initiating.retransmitted++; + job = (job_t*)retransmit_job_create(this->initiating.mid, + this->ike_sa->get_id(this->ike_sa)); + lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); + } + return SUCCESS; +} + +METHOD(task_manager_t, initiate, status_t, + private_task_manager_t *this) +{ + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + status_t status; + exchange_type_t exchange = 0; + + if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) + { + DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", + exchange_type_names, this->initiating.type); + /* do not initiate if we already have a message in the air */ + return SUCCESS; + } + + if (this->active_tasks->get_count(this->active_tasks) == 0) + { + DBG2(DBG_IKE, "activating new tasks"); + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_CREATED: + activate_task(this, TASK_IKE_VENDOR); + if (activate_task(this, TASK_IKE_INIT)) + { + this->initiating.mid = 0; + exchange = IKE_SA_INIT; + activate_task(this, TASK_IKE_NATD); + activate_task(this, TASK_IKE_CERT_PRE); +#ifdef ME + /* this task has to be activated before the TASK_IKE_AUTH + * task, because that task pregenerates the packet after + * which no payloads can be added to the message anymore. + */ + activate_task(this, TASK_IKE_ME); +#endif /* ME */ + activate_task(this, TASK_IKE_AUTH); + activate_task(this, TASK_IKE_CERT_POST); + activate_task(this, TASK_IKE_CONFIG); + activate_task(this, TASK_CHILD_CREATE); + activate_task(this, TASK_IKE_AUTH_LIFETIME); + activate_task(this, TASK_IKE_MOBIKE); + } + break; + case IKE_ESTABLISHED: + if (activate_task(this, TASK_CHILD_CREATE)) + { + exchange = CREATE_CHILD_SA; + break; + } + if (activate_task(this, TASK_CHILD_DELETE)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, TASK_CHILD_REKEY)) + { + exchange = CREATE_CHILD_SA; + break; + } + if (activate_task(this, TASK_IKE_DELETE)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, TASK_IKE_REKEY)) + { + exchange = CREATE_CHILD_SA; + break; + } + if (activate_task(this, TASK_IKE_REAUTH)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, TASK_IKE_MOBIKE)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, TASK_IKE_DPD)) + { + exchange = INFORMATIONAL; + break; + } + if (activate_task(this, TASK_IKE_AUTH_LIFETIME)) + { + exchange = INFORMATIONAL; + break; + } +#ifdef ME + if (activate_task(this, TASK_IKE_ME)) + { + exchange = ME_CONNECT; + break; + } +#endif /* ME */ + case IKE_REKEYING: + if (activate_task(this, TASK_IKE_DELETE)) + { + exchange = INFORMATIONAL; + break; + } + case IKE_DELETING: + default: + break; + } + } + else + { + DBG2(DBG_IKE, "reinitiating already active tasks"); + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); + switch (task->get_type(task)) + { + case TASK_IKE_INIT: + exchange = IKE_SA_INIT; + break; + case TASK_IKE_AUTH: + exchange = IKE_AUTH; + break; + case TASK_CHILD_CREATE: + case TASK_CHILD_REKEY: + case TASK_IKE_REKEY: + exchange = CREATE_CHILD_SA; + break; + case TASK_IKE_MOBIKE: + exchange = INFORMATIONAL; + break; + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + } + + if (exchange == 0) + { + DBG2(DBG_IKE, "nothing to initiate"); + /* nothing to do yet... */ + return SUCCESS; + } + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); + message->set_message_id(message, this->initiating.mid); + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_exchange_type(message, exchange); + this->initiating.type = exchange; + this->initiating.retransmitted = 0; + + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + break; + case FAILED: + default: + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + enumerator->destroy(enumerator); + message->destroy(message); + flush(this); + return DESTROY_ME; + } + } + enumerator->destroy(enumerator); + + /* update exchange type if a task changed it */ + this->initiating.type = message->get_exchange_type(message); + + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->initiating.packet); + if (status != SUCCESS) + { + /* message generation failed. There is nothing more to do than to + * close the SA */ + message->destroy(message); + flush(this); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + message->destroy(message); + + return retransmit(this, this->initiating.mid); +} + +/** + * handle an incoming response message + */ +static status_t process_response(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + task_t *task; + + if (message->get_exchange_type(message) != this->initiating.type) + { + DBG1(DBG_IKE, "received %N response, but expected %N", + exchange_type_names, message->get_exchange_type(message), + exchange_type_names, this->initiating.type); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + /* catch if we get resetted while processing */ + this->reset = FALSE; + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + if (this->reset) + { /* start all over again if we were reset */ + this->reset = FALSE; + enumerator->destroy(enumerator); + return initiate(this); + } + } + enumerator->destroy(enumerator); + + this->initiating.mid++; + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + this->initiating.packet->destroy(this->initiating.packet); + this->initiating.packet = NULL; + + return initiate(this); +} + +/** + * handle exchange collisions + */ +static bool handle_collisions(private_task_manager_t *this, task_t *task) +{ + enumerator_t *enumerator; + task_t *active; + task_type_t type; + + type = task->get_type(task); + + /* do we have to check */ + if (type == TASK_IKE_REKEY || type == TASK_CHILD_REKEY || + type == TASK_CHILD_DELETE || type == TASK_IKE_DELETE || + type == TASK_IKE_REAUTH) + { + /* find an exchange collision, and notify these tasks */ + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&active)) + { + switch (active->get_type(active)) + { + case TASK_IKE_REKEY: + if (type == TASK_IKE_REKEY || type == TASK_IKE_DELETE || + type == TASK_IKE_REAUTH) + { + ike_rekey_t *rekey = (ike_rekey_t*)active; + rekey->collide(rekey, task); + break; + } + continue; + case TASK_CHILD_REKEY: + if (type == TASK_CHILD_REKEY || type == TASK_CHILD_DELETE) + { + child_rekey_t *rekey = (child_rekey_t*)active; + rekey->collide(rekey, task); + break; + } + continue; + default: + continue; + } + enumerator->destroy(enumerator); + return TRUE; + } + enumerator->destroy(enumerator); + } + return FALSE; +} + +/** + * build a response depending on the "passive" task list + */ +static status_t build_response(private_task_manager_t *this, message_t *request) +{ + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + bool delete = FALSE, hook = FALSE; + status_t status; + + me = request->get_destination(request); + other = request->get_source(request); + + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); + message->set_exchange_type(message, request->get_exchange_type(request)); + /* send response along the path the request came in */ + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_message_id(message, this->responding.mid); + message->set_request(message, FALSE); + + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + if (!handle_collisions(this, task)) + { + task->destroy(task); + } + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + if (handle_collisions(this, task)) + { + this->passive_tasks->remove_at(this->passive_tasks, + enumerator); + } + break; + case FAILED: + default: + hook = TRUE; + /* FALL */ + case DESTROY_ME: + /* destroy IKE_SA, but SEND response first */ + delete = TRUE; + break; + } + if (delete) + { + break; + } + } + enumerator->destroy(enumerator); + + /* remove resonder SPI if IKE_SA_INIT failed */ + if (delete && request->get_exchange_type(request) == IKE_SA_INIT) + { + ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); + id->set_responder_spi(id, 0); + } + + /* message complete, send it */ + DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->responding.packet); + message->destroy(message); + if (status != SUCCESS) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + if (delete) + { + if (hook) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + return DESTROY_ME; + } + return SUCCESS; +} + +/** + * handle an incoming request message + */ +static status_t process_request(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + task_t *task = NULL; + payload_t *payload; + notify_payload_t *notify; + delete_payload_t *delete; + + if (this->passive_tasks->get_count(this->passive_tasks) == 0) + { /* create tasks depending on request type, if not already some queued */ + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: + { + task = (task_t*)ike_vendor_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_natd_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); +#ifdef ME + task = (task_t*)ike_me_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); +#endif /* ME */ + task = (task_t*)ike_auth_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_config_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE, + NULL, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + } + case CREATE_CHILD_SA: + { /* FIXME: we should prevent this on mediation connections */ + bool notify_found = FALSE, ts_found = FALSE; + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY: + { /* if we find a rekey notify, its CHILD_SA rekeying */ + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == REKEY_SA && + (notify->get_protocol_id(notify) == PROTO_AH || + notify->get_protocol_id(notify) == PROTO_ESP)) + { + notify_found = TRUE; + } + break; + } + case TRAFFIC_SELECTOR_INITIATOR: + case TRAFFIC_SELECTOR_RESPONDER: + { /* if we don't find a TS, its IKE rekeying */ + ts_found = TRUE; + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); + + if (ts_found) + { + if (notify_found) + { + task = (task_t*)child_rekey_create(this->ike_sa, + PROTO_NONE, 0); + } + else + { + task = (task_t*)child_create_create(this->ike_sa, NULL, + FALSE, NULL, NULL); + } + } + else + { + task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); + } + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + } + case INFORMATIONAL: + { + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY: + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + case NO_ADDITIONAL_ADDRESSES: + case UPDATE_SA_ADDRESSES: + case NO_NATS_ALLOWED: + case UNACCEPTABLE_ADDRESSES: + case UNEXPECTED_NAT_DETECTED: + case COOKIE2: + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + task = (task_t*)ike_mobike_create( + this->ike_sa, FALSE); + break; + case AUTH_LIFETIME: + task = (task_t*)ike_auth_lifetime_create( + this->ike_sa, FALSE); + break; + default: + break; + } + break; + } + case DELETE: + { + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, + FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, + PROTO_NONE, 0, FALSE); + } + break; + } + default: + break; + } + if (task) + { + break; + } + } + enumerator->destroy(enumerator); + + if (task == NULL) + { + task = (task_t*)ike_dpd_create(FALSE); + } + this->passive_tasks->insert_last(this->passive_tasks, task); + break; + } +#ifdef ME + case ME_CONNECT: + { + task = (task_t*)ike_me_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + } +#endif /* ME */ + default: + break; + } + } + + /* let the tasks process the message */ + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs at least another call to build() */ + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + } + enumerator->destroy(enumerator); + + return build_response(this, message); +} + +METHOD(task_manager_t, incr_mid, void, + private_task_manager_t *this, bool initiate) +{ + if (initiate) + { + this->initiating.mid++; + } + else + { + this->responding.mid++; + } +} + +/** + * Send a notify back to the sender + */ +static void send_notify_response(private_task_manager_t *this, + message_t *request, notify_type_t type, + chunk_t data) +{ + message_t *response; + packet_t *packet; + host_t *me, *other; + + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); + response->set_exchange_type(response, request->get_exchange_type(request)); + response->set_request(response, FALSE); + response->set_message_id(response, request->get_message_id(request)); + response->add_notify(response, FALSE, type, data); + me = this->ike_sa->get_my_host(this->ike_sa); + if (me->is_anyaddr(me)) + { + me = request->get_destination(request); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + } + other = this->ike_sa->get_other_host(this->ike_sa); + if (other->is_anyaddr(other)) + { + other = request->get_source(request); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + response->set_source(response, me->clone(me)); + response->set_destination(response, other->clone(other)); + if (this->ike_sa->generate_message(this->ike_sa, response, + &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); +} + +/** + * Parse the given message and verify that it is valid. + */ +static status_t parse_message(private_task_manager_t *this, message_t *msg) +{ + status_t status; + u_int8_t type = 0; + + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + + if (status == SUCCESS) + { /* check for unsupported critical payloads */ + enumerator_t *enumerator; + unknown_payload_t *unknown; + payload_t *payload; + + enumerator = msg->create_payload_enumerator(msg); + while (enumerator->enumerate(enumerator, &payload)) + { + unknown = (unknown_payload_t*)payload; + type = payload->get_type(payload); + if (!payload_is_known(type) && + unknown->is_critical(unknown)) + { + DBG1(DBG_ENC, "payload type %N is not supported, " + "but its critical!", payload_type_names, type); + status = NOT_SUPPORTED; + break; + } + } + enumerator->destroy(enumerator); + } + + if (status != SUCCESS) + { + bool is_request = msg->get_request(msg); + + switch (status) + { + case NOT_SUPPORTED: + DBG1(DBG_IKE, "critical unknown payloads found"); + if (is_request) + { + send_notify_response(this, msg, + UNSUPPORTED_CRITICAL_PAYLOAD, + chunk_from_thing(type)); + incr_mid(this, FALSE); + } + break; + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + /* ignored */ + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + default: + break; + } + DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + exchange_type_names, msg->get_exchange_type(msg), + is_request ? "request" : "response", + msg->get_message_id(msg)); + + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED) + { /* invalid initiation attempt, close SA */ + return DESTROY_ME; + } + } + return status; +} + + +METHOD(task_manager_t, process_message, status_t, + private_task_manager_t *this, message_t *msg) +{ + host_t *me, *other; + status_t status; + u_int32_t mid; + + charon->bus->message(charon->bus, msg, TRUE, FALSE); + status = parse_message(this, msg); + if (status != SUCCESS) + { + return status; + } + + me = msg->get_destination(msg); + other = msg->get_source(msg); + + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) + { + ike_sa_id_t *ike_sa_id; + ike_cfg_t *ike_cfg; + job_t *job; + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); + if (ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", + me, other, notify_type_names, NO_PROPOSAL_CHOSEN); + send_notify_response(this, msg, + NO_PROPOSAL_CHOSEN, chunk_empty); + return DESTROY_ME; + } + this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); + ike_cfg->destroy(ike_cfg); + /* add a timeout if peer does not establish it completely */ + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, + lib->settings->get_int(lib->settings, + "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT, + charon->name)); + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + + mid = msg->get_message_id(msg); + if (msg->get_request(msg)) + { + if (mid == this->responding.mid) + { + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || + this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || + msg->get_exchange_type(msg) != IKE_SA_INIT) + { /* only do host updates based on verified messages */ + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { /* with MOBIKE, we do no implicit updates */ + this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); + } + } + charon->bus->message(charon->bus, msg, TRUE, TRUE); + if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) + { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ + return SUCCESS; + } + if (process_request(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + this->responding.mid++; + } + else if ((mid == this->responding.mid - 1) && this->responding.packet) + { + packet_t *clone; + host_t *host; + + DBG1(DBG_IKE, "received retransmit of request with ID %d, " + "retransmitting response", mid); + clone = this->responding.packet->clone(this->responding.packet); + host = msg->get_destination(msg); + clone->set_source(clone, host->clone(host)); + host = msg->get_source(msg); + clone->set_destination(clone, host->clone(host)); + charon->sender->send(charon->sender, clone); + } + else + { + DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", + mid, this->responding.mid); + } + } + else + { + if (mid == this->initiating.mid) + { + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || + this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || + msg->get_exchange_type(msg) != IKE_SA_INIT) + { /* only do host updates based on verified messages */ + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { /* with MOBIKE, we do no implicit updates */ + this->ike_sa->update_hosts(this->ike_sa, me, other, FALSE); + } + } + charon->bus->message(charon->bus, msg, TRUE, TRUE); + if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) + { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ + return SUCCESS; + } + if (process_response(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + } + else + { + DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", + mid, this->initiating.mid); + return SUCCESS; + } + } + return SUCCESS; +} + +METHOD(task_manager_t, queue_task, void, + private_task_manager_t *this, task_t *task) +{ + if (task->get_type(task) == TASK_IKE_MOBIKE) + { /* there is no need to queue more than one mobike task */ + enumerator_t *enumerator; + task_t *current; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->get_type(current) == TASK_IKE_MOBIKE) + { + enumerator->destroy(enumerator); + task->destroy(task); + return; + } + } + enumerator->destroy(enumerator); + } + DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); + this->queued_tasks->insert_last(this->queued_tasks, task); +} + +/** + * Check if a given task has been queued already + */ +static bool has_queued(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + bool found = FALSE; + task_t *task; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == type) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +METHOD(task_manager_t, queue_ike, void, + private_task_manager_t *this) +{ + if (!has_queued(this, TASK_IKE_VENDOR)) + { + queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_INIT)) + { + queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); + } + if (!has_queued(this, TASK_IKE_NATD)) + { + queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_CERT_PRE)) + { + queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_AUTH)) + { + queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_CERT_POST)) + { + queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_CONFIG)) + { + queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_AUTH_LIFETIME)) + { + queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_MOBIKE)) + { + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->use_mobike(peer_cfg)) + { + queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); + } + } +#ifdef ME + if (!has_queued(this, TASK_IKE_ME)) + { + queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); + } +#endif /* ME */ +} + +METHOD(task_manager_t, queue_ike_rekey, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE)); +} + +METHOD(task_manager_t, queue_ike_reauth, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_reauth_create(this->ike_sa)); +} + +METHOD(task_manager_t, queue_ike_delete, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_delete_create(this->ike_sa, TRUE)); +} + +METHOD(task_manager_t, queue_mobike, void, + private_task_manager_t *this, bool roam, bool address) +{ + ike_mobike_t *mobike; + + mobike = ike_mobike_create(this->ike_sa, TRUE); + if (roam) + { + mobike->roam(mobike, address); + } + else + { + mobike->addresses(mobike); + } + queue_task(this, &mobike->task); +} + +METHOD(task_manager_t, queue_child, void, + private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + child_create_t *task; + + task = child_create_create(this->ike_sa, cfg, FALSE, tsi, tsr); + if (reqid) + { + task->use_reqid(task, reqid); + } + queue_task(this, &task->task); +} + +METHOD(task_manager_t, queue_child_rekey, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + queue_task(this, (task_t*)child_rekey_create(this->ike_sa, protocol, spi)); +} + +METHOD(task_manager_t, queue_child_delete, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi, + bool expired) +{ + queue_task(this, (task_t*)child_delete_create(this->ike_sa, + protocol, spi, expired)); +} + +METHOD(task_manager_t, queue_dpd, void, + private_task_manager_t *this) +{ + ike_mobike_t *mobike; + + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE) && + this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) + { + /* use mobike enabled DPD to detect NAT mapping changes */ + mobike = ike_mobike_create(this->ike_sa, TRUE); + mobike->dpd(mobike); + queue_task(this, &mobike->task); + } + else + { + queue_task(this, (task_t*)ike_dpd_create(TRUE)); + } +} + +METHOD(task_manager_t, adopt_tasks, void, + private_task_manager_t *this, task_manager_t *other_public) +{ + private_task_manager_t *other = (private_task_manager_t*)other_public; + task_t *task; + + /* move queued tasks from other to this */ + while (other->queued_tasks->remove_last(other->queued_tasks, + (void**)&task) == SUCCESS) + { + DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } +} + +METHOD(task_manager_t, busy, bool, + private_task_manager_t *this) +{ + return (this->active_tasks->get_count(this->active_tasks) > 0); +} + +METHOD(task_manager_t, reset, void, + private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) +{ + enumerator_t *enumerator; + task_t *task; + + /* reset message counters and retransmit packets */ + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + this->responding.packet = NULL; + this->initiating.packet = NULL; + if (initiate != UINT_MAX) + { + this->initiating.mid = initiate; + } + if (respond != UINT_MAX) + { + this->responding.mid = respond; + } + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + + /* reset queued tasks */ + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + task->migrate(task, this->ike_sa); + } + enumerator->destroy(enumerator); + + /* reset active tasks */ + while (this->active_tasks->remove_last(this->active_tasks, + (void**)&task) == SUCCESS) + { + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } + + this->reset = TRUE; +} + +METHOD(task_manager_t, create_task_enumerator, enumerator_t*, + private_task_manager_t *this, task_queue_t queue) +{ + switch (queue) + { + case TASK_QUEUE_ACTIVE: + return this->active_tasks->create_enumerator(this->active_tasks); + case TASK_QUEUE_PASSIVE: + return this->passive_tasks->create_enumerator(this->passive_tasks); + case TASK_QUEUE_QUEUED: + return this->queued_tasks->create_enumerator(this->queued_tasks); + default: + return enumerator_create_empty(); + } +} + +METHOD(task_manager_t, destroy, void, + private_task_manager_t *this) +{ + flush(this); + + this->active_tasks->destroy(this->active_tasks); + this->queued_tasks->destroy(this->queued_tasks); + this->passive_tasks->destroy(this->passive_tasks); + + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + free(this); +} + +/* + * see header file + */ +task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) +{ + private_task_manager_t *this; + + INIT(this, + .public = { + .task_manager = { + .process_message = _process_message, + .queue_task = _queue_task, + .queue_ike = _queue_ike, + .queue_ike_rekey = _queue_ike_rekey, + .queue_ike_reauth = _queue_ike_reauth, + .queue_ike_delete = _queue_ike_delete, + .queue_mobike = _queue_mobike, + .queue_child = _queue_child, + .queue_child_rekey = _queue_child_rekey, + .queue_child_delete = _queue_child_delete, + .queue_dpd = _queue_dpd, + .initiate = _initiate, + .retransmit = _retransmit, + .incr_mid = _incr_mid, + .reset = _reset, + .adopt_tasks = _adopt_tasks, + .busy = _busy, + .create_task_enumerator = _create_task_enumerator, + .flush_queue = _flush_queue, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiating.type = EXCHANGE_TYPE_UNDEFINED, + .queued_tasks = linked_list_create(), + .active_tasks = linked_list_create(), + .passive_tasks = linked_list_create(), + .retransmit_tries = lib->settings->get_int(lib->settings, + "%s.retransmit_tries", RETRANSMIT_TRIES, charon->name), + .retransmit_timeout = lib->settings->get_double(lib->settings, + "%s.retransmit_timeout", RETRANSMIT_TIMEOUT, charon->name), + .retransmit_base = lib->settings->get_double(lib->settings, + "%s.retransmit_base", RETRANSMIT_BASE, charon->name), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/task_manager_v2.h b/src/libcharon/sa/ikev2/task_manager_v2.h new file mode 100644 index 000000000..70444ae27 --- /dev/null +++ b/src/libcharon/sa/ikev2/task_manager_v2.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup task_manager_v2 task_manager_v2 + * @{ @ingroup ikev2 + */ + +#ifndef TASK_MANAGER_V2_H_ +#define TASK_MANAGER_V2_H_ + +typedef struct task_manager_v2_t task_manager_v2_t; + +#include + +/** + * Task manager, IKEv2 variant. + */ +struct task_manager_v2_t { + + /** + * Implements task_manager_t. + */ + task_manager_t task_manager; +}; + +/** + * Create an instance of the task manager. + * + * @param ike_sa IKE_SA to manage. + */ +task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa); + +#endif /** TASK_MANAGER_V2_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c new file mode 100644 index 000000000..46a165546 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -0,0 +1,1426 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "child_create.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct private_child_create_t private_child_create_t; + +/** + * Private members of a child_create_t task. + */ +struct private_child_create_t { + + /** + * Public methods and task_t interface. + */ + child_create_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * nonce chosen by us + */ + chunk_t my_nonce; + + /** + * nonce chosen by peer + */ + chunk_t other_nonce; + + /** + * config to create the CHILD_SA from + */ + child_cfg_t *config; + + /** + * list of proposal candidates + */ + linked_list_t *proposals; + + /** + * selected proposal to use for CHILD_SA + */ + proposal_t *proposal; + + /** + * traffic selectors for initiators side + */ + linked_list_t *tsi; + + /** + * traffic selectors for responders side + */ + linked_list_t *tsr; + + /** + * source of triggering packet + */ + traffic_selector_t *packet_tsi; + + /** + * destination of triggering packet + */ + traffic_selector_t *packet_tsr; + + /** + * optional diffie hellman exchange + */ + diffie_hellman_t *dh; + + /** + * group used for DH exchange + */ + diffie_hellman_group_t dh_group; + + /** + * IKE_SAs keymat + */ + keymat_v2_t *keymat; + + /** + * mode the new CHILD_SA uses (transport/tunnel/beet) + */ + ipsec_mode_t mode; + + /** + * peer accepts TFC padding for this SA + */ + bool tfcv3; + + /** + * IPComp transform to use + */ + ipcomp_transform_t ipcomp; + + /** + * IPComp transform proposed or accepted by the other peer + */ + ipcomp_transform_t ipcomp_received; + + /** + * Own allocated SPI + */ + u_int32_t my_spi; + + /** + * SPI received in proposal + */ + u_int32_t other_spi; + + /** + * Own allocated Compression Parameter Index (CPI) + */ + u_int16_t my_cpi; + + /** + * Other Compression Parameter Index (CPI), received via IPCOMP_SUPPORTED + */ + u_int16_t other_cpi; + + /** + * reqid to use if we are rekeying + */ + u_int32_t reqid; + + /** + * CHILD_SA which gets established + */ + child_sa_t *child_sa; + + /** + * successfully established the CHILD? + */ + bool established; + + /** + * whether the CHILD_SA rekeys an existing one + */ + bool rekey; + + /** + * whether we are retrying with another DH group + */ + bool retry; +}; + +/** + * get the nonce from a message + */ +static status_t get_nonce(message_t *message, chunk_t *nonce) +{ + nonce_payload_t *payload; + + payload = (nonce_payload_t*)message->get_payload(message, NONCE); + if (payload == NULL) + { + return FAILED; + } + *nonce = payload->get_nonce(payload); + return NEED_MORE; +} + +/** + * generate a new nonce to include in a CREATE_CHILD_SA message + */ +static status_t generate_nonce(private_child_create_t *this) +{ + nonce_gen_t *nonceg; + + nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); + if (!nonceg) + { + DBG1(DBG_IKE, "no nonce generator found to create nonce"); + return FAILED; + } + if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce)) + { + DBG1(DBG_IKE, "nonce allocation failed"); + nonceg->destroy(nonceg); + return FAILED; + } + nonceg->destroy(nonceg); + + return SUCCESS; +} + +/** + * Check a list of traffic selectors if any selector belongs to host + */ +static bool ts_list_is_host(linked_list_t *list, host_t *host) +{ + traffic_selector_t *ts; + bool is_host = TRUE; + enumerator_t *enumerator = list->create_enumerator(list); + + while (is_host && enumerator->enumerate(enumerator, (void**)&ts)) + { + is_host = is_host && ts->is_host(ts, host); + } + enumerator->destroy(enumerator); + return is_host; +} + +/** + * Allocate SPIs and update proposals + */ +static bool allocate_spi(private_child_create_t *this) +{ + enumerator_t *enumerator; + proposal_t *proposal; + + /* TODO: allocate additional SPI for AH if we have such proposals */ + this->my_spi = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (this->my_spi) + { + if (this->initiator) + { + enumerator = this->proposals->create_enumerator(this->proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + proposal->set_spi(proposal, this->my_spi); + } + enumerator->destroy(enumerator); + } + else + { + this->proposal->set_spi(this->proposal, this->my_spi); + } + return TRUE; + } + return FALSE; +} + +/** + * Schedule inactivity timeout for CHILD_SA with reqid, if enabled + */ +static void schedule_inactivity_timeout(private_child_create_t *this) +{ + u_int32_t timeout; + bool close_ike; + + timeout = this->config->get_inactivity(this->config); + if (timeout) + { + close_ike = lib->settings->get_bool(lib->settings, + "%s.inactivity_close_ike", FALSE, charon->name); + lib->scheduler->schedule_job(lib->scheduler, (job_t*) + inactivity_job_create(this->child_sa->get_reqid(this->child_sa), + timeout, close_ike), timeout); + } +} + +/** + * Check if we have a an address pool configured + */ +static bool have_pool(ike_sa_t *ike_sa) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + char *pool; + bool found = FALSE; + + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_pool_enumerator(peer_cfg); + if (enumerator->enumerate(enumerator, &pool)) + { + found = TRUE; + } + enumerator->destroy(enumerator); + } + return found; +} + +/** + * Get hosts to use for dynamic traffic selectors + */ +static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local) +{ + enumerator_t *enumerator; + linked_list_t *list; + host_t *host; + + list = linked_list_create(); + enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local); + while (enumerator->enumerate(enumerator, &host)) + { + list->insert_last(list, host); + } + enumerator->destroy(enumerator); + + if (list->get_count(list) == 0) + { /* no virtual IPs assigned */ + if (local) + { + host = ike_sa->get_my_host(ike_sa); + list->insert_last(list, host); + } + else if (!have_pool(ike_sa)) + { /* use host only if we don't have a pool configured */ + host = ike_sa->get_other_host(ike_sa); + list->insert_last(list, host); + } + } + return list; +} + +/** + * Install a CHILD_SA for usage, return value: + * - FAILED: no acceptable proposal + * - INVALID_ARG: diffie hellman group inacceptable + * - NOT_FOUND: TS inacceptable + */ +static status_t select_and_install(private_child_create_t *this, + bool no_dh, bool ike_auth) +{ + status_t status, status_i, status_o; + chunk_t nonce_i, nonce_r; + chunk_t encr_i = chunk_empty, encr_r = chunk_empty; + chunk_t integ_i = chunk_empty, integ_r = chunk_empty; + linked_list_t *my_ts, *other_ts, *list; + host_t *me, *other; + bool private; + + if (this->proposals == NULL) + { + DBG1(DBG_IKE, "SA payload missing in message"); + return FAILED; + } + if (this->tsi == NULL || this->tsr == NULL) + { + DBG1(DBG_IKE, "TS payloads missing in message"); + return NOT_FOUND; + } + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + + private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN); + this->proposal = this->config->select_proposal(this->config, + this->proposals, no_dh, private); + if (this->proposal == NULL) + { + DBG1(DBG_IKE, "no acceptable proposal found"); + return FAILED; + } + this->other_spi = this->proposal->get_spi(this->proposal); + + if (!this->initiator && !allocate_spi(this)) + { /* responder has no SPI allocated yet */ + DBG1(DBG_IKE, "allocating SPI failed"); + return FAILED; + } + this->child_sa->set_proposal(this->child_sa, this->proposal); + + if (!this->proposal->has_dh_group(this->proposal, this->dh_group)) + { + u_int16_t group; + + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &group, NULL)) + { + DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + return INVALID_ARG; + } + /* the selected proposal does not use a DH group */ + DBG1(DBG_IKE, "ignoring KE exchange, agreed on a non-PFS proposal"); + DESTROY_IF(this->dh); + this->dh = NULL; + this->dh_group = MODP_NONE; + } + + if (this->initiator) + { + nonce_i = this->my_nonce; + nonce_r = this->other_nonce; + my_ts = this->tsi; + other_ts = this->tsr; + } + else + { + nonce_r = this->my_nonce; + nonce_i = this->other_nonce; + my_ts = this->tsr; + other_ts = this->tsi; + } + list = get_dynamic_hosts(this->ike_sa, TRUE); + my_ts = this->config->get_traffic_selectors(this->config, + TRUE, my_ts, list); + list->destroy(list); + list = get_dynamic_hosts(this->ike_sa, FALSE); + other_ts = this->config->get_traffic_selectors(this->config, + FALSE, other_ts, list); + list->destroy(list); + + if (this->initiator) + { + if (ike_auth) + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_POST_NOAUTH, my_ts, other_ts); + } + else + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_POST_AUTH, my_ts, other_ts); + } + } + else + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER, my_ts, other_ts); + } + + if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + { + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + DBG1(DBG_IKE, "no acceptable traffic selectors found"); + return NOT_FOUND; + } + + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); + this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); + if (this->initiator) + { + this->tsi = my_ts; + this->tsr = other_ts; + } + else + { + this->tsr = my_ts; + this->tsi = other_ts; + } + + if (!this->initiator) + { + /* check if requested mode is acceptable, downgrade if required */ + switch (this->mode) + { + case MODE_TRANSPORT: + if (!this->config->use_proxy_mode(this->config) && + (!ts_list_is_host(this->tsi, other) || + !ts_list_is_host(this->tsr, me)) + ) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using transport mode, not host-to-host"); + } + else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using transport mode, connection NATed"); + } + break; + case MODE_BEET: + if (!ts_list_is_host(this->tsi, NULL) || + !ts_list_is_host(this->tsr, NULL)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using BEET mode, not host-to-host"); + } + break; + default: + break; + } + } + + this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); + this->child_sa->set_ipcomp(this->child_sa, this->ipcomp); + this->child_sa->set_mode(this->child_sa, this->mode); + this->child_sa->set_protocol(this->child_sa, + this->proposal->get_protocol(this->proposal)); + + if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE) + { + this->my_cpi = this->other_cpi = 0; + this->ipcomp = IPCOMP_NONE; + } + status_i = status_o = FAILED; + if (this->keymat->derive_child_keys(this->keymat, this->proposal, + this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) + { + if (this->initiator) + { + status_i = this->child_sa->install(this->child_sa, + encr_r, integ_r, this->my_spi, this->my_cpi, + TRUE, this->tfcv3, my_ts, other_ts); + status_o = this->child_sa->install(this->child_sa, + encr_i, integ_i, this->other_spi, this->other_cpi, + FALSE, this->tfcv3, my_ts, other_ts); + } + else + { + status_i = this->child_sa->install(this->child_sa, + encr_i, integ_i, this->my_spi, this->my_cpi, + TRUE, this->tfcv3, my_ts, other_ts); + status_o = this->child_sa->install(this->child_sa, + encr_r, integ_r, this->other_spi, this->other_cpi, + FALSE, this->tfcv3, my_ts, other_ts); + } + } + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); + + if (status_i != SUCCESS || status_o != SUCCESS) + { + DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel", + (status_i != SUCCESS) ? "inbound " : "", + (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", + (status_o != SUCCESS) ? "outbound " : ""); + return FAILED; + } + + if (this->initiator) + { + status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts); + } + else + { + /* use a copy of the traffic selectors, as the POST hook should not + * change payloads */ + my_ts = this->tsr->clone_offset(this->tsr, + offsetof(traffic_selector_t, clone)); + other_ts = this->tsi->clone_offset(this->tsi, + offsetof(traffic_selector_t, clone)); + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER_POST, my_ts, other_ts); + if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + { + status = FAILED; + } + else + { + status = this->child_sa->add_policies(this->child_sa, + my_ts, other_ts); + } + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + } + if (status != SUCCESS) + { + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); + return NOT_FOUND; + } + + charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, + this->dh, nonce_i, nonce_r); + + /* add to IKE_SA, and remove from task */ + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + this->established = TRUE; + + if (!this->rekey) + { /* a rekeyed SA uses the same reqid, no need for a new job */ + schedule_inactivity_timeout(this); + } + return SUCCESS; +} + +/** + * build the payloads for the message + */ +static void build_payloads(private_child_create_t *this, message_t *message) +{ + sa_payload_t *sa_payload; + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + ts_payload_t *ts_payload; + + /* add SA payload */ + if (this->initiator) + { + sa_payload = sa_payload_create_from_proposals_v2(this->proposals); + } + else + { + sa_payload = sa_payload_create_from_proposal_v2(this->proposal); + } + message->add_payload(message, (payload_t*)sa_payload); + + /* add nonce payload if not in IKE_AUTH */ + if (message->get_exchange_type(message) == CREATE_CHILD_SA) + { + nonce_payload = nonce_payload_create(NONCE); + nonce_payload->set_nonce(nonce_payload, this->my_nonce); + message->add_payload(message, (payload_t*)nonce_payload); + } + + /* diffie hellman exchange, if PFS enabled */ + if (this->dh) + { + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE, + this->dh); + message->add_payload(message, (payload_t*)ke_payload); + } + + /* add TSi/TSr payloads */ + ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); + message->add_payload(message, (payload_t*)ts_payload); + ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr); + message->add_payload(message, (payload_t*)ts_payload); + + /* add a notify if we are not in tunnel mode */ + switch (this->mode) + { + case MODE_TRANSPORT: + message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty); + break; + case MODE_BEET: + message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty); + break; + default: + break; + } +} + +/** + * Adds an IPCOMP_SUPPORTED notify to the message, allocating a CPI + */ +static void add_ipcomp_notify(private_child_create_t *this, + message_t *message, u_int8_t ipcomp) +{ + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, " + "IPComp disabled"); + return; + } + + this->my_cpi = this->child_sa->alloc_cpi(this->child_sa); + if (this->my_cpi) + { + this->ipcomp = ipcomp; + message->add_notify(message, FALSE, IPCOMP_SUPPORTED, + chunk_cata("cc", chunk_from_thing(this->my_cpi), + chunk_from_thing(ipcomp))); + } + else + { + DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled"); + } +} + +/** + * handle a received notify payload + */ +static void handle_notify(private_child_create_t *this, notify_payload_t *notify) +{ + switch (notify->get_notify_type(notify)) + { + case USE_TRANSPORT_MODE: + this->mode = MODE_TRANSPORT; + break; + case USE_BEET_MODE: + if (this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)) + { /* handle private use notify only if we know its meaning */ + this->mode = MODE_BEET; + } + else + { + DBG1(DBG_IKE, "received a notify strongSwan uses for BEET " + "mode, but peer implementation unknown, skipped"); + } + break; + case IPCOMP_SUPPORTED: + { + ipcomp_transform_t ipcomp; + u_int16_t cpi; + chunk_t data; + + data = notify->get_notification_data(notify); + cpi = *(u_int16_t*)data.ptr; + ipcomp = (ipcomp_transform_t)(*(data.ptr + 2)); + switch (ipcomp) + { + case IPCOMP_DEFLATE: + this->other_cpi = cpi; + this->ipcomp_received = ipcomp; + break; + case IPCOMP_LZS: + case IPCOMP_LZJH: + default: + DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a " + "transform ID we don't support %N", + ipcomp_transform_names, ipcomp); + break; + } + break; + } + case ESP_TFC_PADDING_NOT_SUPPORTED: + DBG1(DBG_IKE, "received %N, not using ESPv3 TFC padding", + notify_type_names, notify->get_notify_type(notify)); + this->tfcv3 = FALSE; + break; + default: + break; + } +} + +/** + * Read payloads from message + */ +static void process_payloads(private_child_create_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + sa_payload_t *sa_payload; + ke_payload_t *ke_payload; + ts_payload_t *ts_payload; + + /* defaults to TUNNEL mode */ + this->mode = MODE_TUNNEL; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case SECURITY_ASSOCIATION: + sa_payload = (sa_payload_t*)payload; + this->proposals = sa_payload->get_proposals(sa_payload); + break; + case KEY_EXCHANGE: + ke_payload = (ke_payload_t*)payload; + if (!this->initiator) + { + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + this->dh = this->keymat->keymat.create_dh( + &this->keymat->keymat, this->dh_group); + } + if (this->dh) + { + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + } + break; + case TRAFFIC_SELECTOR_INITIATOR: + ts_payload = (ts_payload_t*)payload; + this->tsi = ts_payload->get_traffic_selectors(ts_payload); + break; + case TRAFFIC_SELECTOR_RESPONDER: + ts_payload = (ts_payload_t*)payload; + this->tsr = ts_payload->get_traffic_selectors(ts_payload); + break; + case NOTIFY: + handle_notify(this, (notify_payload_t*)payload); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_child_create_t *this, message_t *message) +{ + enumerator_t *enumerator; + host_t *vip; + peer_cfg_t *peer_cfg; + linked_list_t *list; + + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: + return get_nonce(message, &this->my_nonce); + case CREATE_CHILD_SA: + if (generate_nonce(this) != SUCCESS) + { + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + return SUCCESS; + } + if (!this->retry) + { + this->dh_group = this->config->get_dh_group(this->config); + } + break; + case IKE_AUTH: + if (message->get_message_id(message) != 1) + { + /* send only in the first request, not in subsequent rounds */ + return NEED_MORE; + } + break; + default: + break; + } + + if (this->reqid) + { + DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}", + this->config->get_name(this->config), this->reqid); + } + else + { + DBG0(DBG_IKE, "establishing CHILD_SA %s", + this->config->get_name(this->config)); + } + + /* check if we want a virtual IP, but don't have one */ + list = linked_list_create(); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!this->reqid) + { + enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg); + while (enumerator->enumerate(enumerator, &vip)) + { + /* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */ + vip = host_create_any(vip->get_family(vip)); + list->insert_last(list, vip); + } + enumerator->destroy(enumerator); + } + if (list->get_count(list)) + { + this->tsi = this->config->get_traffic_selectors(this->config, + TRUE, NULL, list); + list->destroy_offset(list, offsetof(host_t, destroy)); + } + else + { /* no virtual IPs configured */ + list->destroy(list); + list = get_dynamic_hosts(this->ike_sa, TRUE); + this->tsi = this->config->get_traffic_selectors(this->config, + TRUE, NULL, list); + list->destroy(list); + } + list = get_dynamic_hosts(this->ike_sa, FALSE); + this->tsr = this->config->get_traffic_selectors(this->config, + FALSE, NULL, list); + list->destroy(list); + + if (this->packet_tsi) + { + this->tsi->insert_first(this->tsi, + this->packet_tsi->clone(this->packet_tsi)); + } + if (this->packet_tsr) + { + this->tsr->insert_first(this->tsr, + this->packet_tsr->clone(this->packet_tsr)); + } + this->proposals = this->config->get_proposals(this->config, + this->dh_group == MODP_NONE); + this->mode = this->config->get_mode(this->config); + if (this->mode == MODE_TRANSPORT && + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + this->mode = MODE_TUNNEL; + DBG1(DBG_IKE, "not using transport mode, connection NATed"); + } + + this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + + if (!allocate_spi(this)) + { + DBG1(DBG_IKE, "unable to allocate SPIs from kernel"); + return FAILED; + } + + if (this->dh_group != MODP_NONE) + { + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); + } + + if (this->config->use_ipcomp(this->config)) + { + /* IPCOMP_DEFLATE is the only transform we support at the moment */ + add_ipcomp_notify(this, message, IPCOMP_DEFLATE); + } + + if (message->get_exchange_type(message) == IKE_AUTH) + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_PRE_NOAUTH, this->tsi, this->tsr); + } + else + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_PRE_AUTH, this->tsi, this->tsr); + } + + build_payloads(this, message); + + this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); + this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); + this->tsi = NULL; + this->tsr = NULL; + this->proposals = NULL; + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_child_create_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: + return get_nonce(message, &this->other_nonce); + case CREATE_CHILD_SA: + get_nonce(message, &this->other_nonce); + break; + case IKE_AUTH: + if (message->get_message_id(message) != 1) + { + /* only handle first AUTH payload, not additional rounds */ + return NEED_MORE; + } + default: + break; + } + + process_payloads(this, message); + + return NEED_MORE; +} + +/** + * handle CHILD_SA setup failure + */ +static void handle_child_sa_failure(private_child_create_t *this, + message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + lib->settings->get_bool(lib->settings, + "%s.close_ike_on_child_failure", FALSE, charon->name)) + { + /* we delay the delete for 100ms, as the IKE_AUTH response must arrive + * first */ + DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure"); + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) + delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), + 100); + } + else + { + DBG1(DBG_IKE, "failed to establish CHILD_SA, keeping IKE_SA"); + } +} + +METHOD(task_t, build_r, status_t, + private_child_create_t *this, message_t *message) +{ + peer_cfg_t *peer_cfg; + payload_t *payload; + enumerator_t *enumerator; + bool no_dh = TRUE, ike_auth = FALSE; + + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: + return get_nonce(message, &this->my_nonce); + case CREATE_CHILD_SA: + if (generate_nonce(this) != SUCCESS) + { + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, + chunk_empty); + return SUCCESS; + } + no_dh = FALSE; + break; + case IKE_AUTH: + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ + return NEED_MORE; + } + ike_auth = TRUE; + default: + break; + } + + if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) + { + DBG1(DBG_IKE, "unable to create CHILD_SA while rekeying IKE_SA"); + message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty); + return SUCCESS; + } + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!this->config && peer_cfg && this->tsi && this->tsr) + { + linked_list_t *listr, *listi; + + listr = get_dynamic_hosts(this->ike_sa, TRUE); + listi = get_dynamic_hosts(this->ike_sa, FALSE); + this->config = peer_cfg->select_child_cfg(peer_cfg, + this->tsr, this->tsi, listr, listi); + listr->destroy(listr); + listi->destroy(listi); + } + + if (this->config == NULL) + { + DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable", + this->tsr, this->tsi); + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + handle_child_sa_failure(this, message); + return SUCCESS; + } + + /* check if ike_config_t included non-critical error notifies */ + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + + switch (notify->get_notify_type(notify)) + { + case INTERNAL_ADDRESS_FAILURE: + case FAILED_CP_REQUIRED: + { + DBG1(DBG_IKE,"configuration payload negotiation " + "failed, no CHILD_SA built"); + enumerator->destroy(enumerator); + handle_child_sa_failure(this, message); + return SUCCESS; + } + default: + break; + } + } + } + enumerator->destroy(enumerator); + + this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, + this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); + + if (this->ipcomp_received != IPCOMP_NONE) + { + if (this->config->use_ipcomp(this->config)) + { + add_ipcomp_notify(this, message, this->ipcomp_received); + } + else + { + DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring", + notify_type_names, IPCOMP_SUPPORTED); + } + } + + switch (select_and_install(this, no_dh, ike_auth)) + { + case SUCCESS: + break; + case NOT_FOUND: + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + handle_child_sa_failure(this, message); + return SUCCESS; + case INVALID_ARG: + { + u_int16_t group = htons(this->dh_group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + handle_child_sa_failure(this, message); + return SUCCESS; + } + case FAILED: + default: + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + handle_child_sa_failure(this, message); + return SUCCESS; + } + + build_payloads(this, message); + + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + + if (!this->rekey) + { /* invoke the child_up() hook if we are not rekeying */ + charon->bus->child_updown(charon->bus, this->child_sa, TRUE); + } + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_child_create_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool no_dh = TRUE, ike_auth = FALSE; + + switch (message->get_exchange_type(message)) + { + case IKE_SA_INIT: + return get_nonce(message, &this->other_nonce); + case CREATE_CHILD_SA: + get_nonce(message, &this->other_nonce); + no_dh = FALSE; + break; + case IKE_AUTH: + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ + return NEED_MORE; + } + ike_auth = TRUE; + default: + break; + } + + /* check for erronous notifies */ + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + notify_type_t type = notify->get_notify_type(notify); + + switch (type) + { + /* handle notify errors related to CHILD_SA only */ + case NO_PROPOSAL_CHOSEN: + case SINGLE_PAIR_REQUIRED: + case NO_ADDITIONAL_SAS: + case INTERNAL_ADDRESS_FAILURE: + case FAILED_CP_REQUIRED: + case TS_UNACCEPTABLE: + case INVALID_SELECTORS: + { + DBG1(DBG_IKE, "received %N notify, no CHILD_SA built", + notify_type_names, type); + enumerator->destroy(enumerator); + handle_child_sa_failure(this, message); + /* an error in CHILD_SA creation is not critical */ + return SUCCESS; + } + case INVALID_KE_PAYLOAD: + { + chunk_t data; + u_int16_t group = MODP_NONE; + + data = notify->get_notification_data(notify); + if (data.len == sizeof(group)) + { + memcpy(&group, data.ptr, data.len); + group = ntohs(group); + } + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + this->dh_group, diffie_hellman_group_names, group); + this->retry = TRUE; + this->dh_group = group; + this->public.task.migrate(&this->public.task, this->ike_sa); + enumerator->destroy(enumerator); + return NEED_MORE; + } + default: + { + if (message->get_exchange_type(message) == CREATE_CHILD_SA) + { /* handle notifies if not handled in IKE_AUTH */ + if (type <= 16383) + { + DBG1(DBG_IKE, "received %N notify error", + notify_type_names, type); + enumerator->destroy(enumerator); + return SUCCESS; + } + DBG2(DBG_IKE, "received %N notify", + notify_type_names, type); + } + break; + } + } + } + } + enumerator->destroy(enumerator); + + process_payloads(this, message); + + if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE) + { + DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting" + " one, no CHILD_SA built"); + handle_child_sa_failure(this, message); + return SUCCESS; + } + else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE) + { + DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, " + "IPComp is disabled"); + this->ipcomp = IPCOMP_NONE; + } + else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received) + { + DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, " + "no CHILD_SA built"); + handle_child_sa_failure(this, message); + return SUCCESS; + } + + if (select_and_install(this, no_dh, ike_auth) == SUCCESS) + { + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + + if (!this->rekey) + { /* invoke the child_up() hook if we are not rekeying */ + charon->bus->child_updown(charon->bus, this->child_sa, TRUE); + } + } + else + { + handle_child_sa_failure(this, message); + } + return SUCCESS; +} + +METHOD(child_create_t, use_reqid, void, + private_child_create_t *this, u_int32_t reqid) +{ + this->reqid = reqid; +} + +METHOD(child_create_t, get_child, child_sa_t*, + private_child_create_t *this) +{ + return this->child_sa; +} + +METHOD(child_create_t, set_config, void, + private_child_create_t *this, child_cfg_t *cfg) +{ + DESTROY_IF(this->config); + this->config = cfg; +} + +METHOD(child_create_t, get_lower_nonce, chunk_t, + private_child_create_t *this) +{ + if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, + min(this->my_nonce.len, this->other_nonce.len)) < 0) + { + return this->my_nonce; + } + else + { + return this->other_nonce; + } +} + +METHOD(task_t, get_type, task_type_t, + private_child_create_t *this) +{ + return TASK_CHILD_CREATE; +} + +METHOD(task_t, migrate, void, + private_child_create_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->my_nonce); + chunk_free(&this->other_nonce); + if (this->tsr) + { + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); + } + if (this->tsi) + { + this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); + } + DESTROY_IF(this->child_sa); + DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); + if (this->proposals) + { + this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); + } + + this->ike_sa = ike_sa; + this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + this->proposal = NULL; + this->proposals = NULL; + this->tsi = NULL; + this->tsr = NULL; + this->dh = NULL; + this->child_sa = NULL; + this->mode = MODE_TUNNEL; + this->ipcomp = IPCOMP_NONE; + this->ipcomp_received = IPCOMP_NONE; + this->other_cpi = 0; + this->reqid = 0; + this->established = FALSE; +} + +METHOD(task_t, destroy, void, + private_child_create_t *this) +{ + chunk_free(&this->my_nonce); + chunk_free(&this->other_nonce); + if (this->tsr) + { + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); + } + if (this->tsi) + { + this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); + } + if (!this->established) + { + DESTROY_IF(this->child_sa); + } + DESTROY_IF(this->packet_tsi); + DESTROY_IF(this->packet_tsr); + DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); + if (this->proposals) + { + this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); + } + + DESTROY_IF(this->config); + free(this); +} + +/* + * Described in header. + */ +child_create_t *child_create_create(ike_sa_t *ike_sa, + child_cfg_t *config, bool rekey, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + private_child_create_t *this; + + INIT(this, + .public = { + .get_child = _get_child, + .set_config = _set_config, + .get_lower_nonce = _get_lower_nonce, + .use_reqid = _use_reqid, + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .config = config, + .packet_tsi = tsi ? tsi->clone(tsi) : NULL, + .packet_tsr = tsr ? tsr->clone(tsr) : NULL, + .dh_group = MODP_NONE, + .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), + .mode = MODE_TUNNEL, + .tfcv3 = TRUE, + .ipcomp = IPCOMP_NONE, + .ipcomp_received = IPCOMP_NONE, + .rekey = rekey, + .retry = FALSE, + ); + + if (config) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + this->initiator = TRUE; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + this->initiator = FALSE; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/child_create.h b/src/libcharon/sa/ikev2/tasks/child_create.h new file mode 100644 index 000000000..d29ba3d98 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_create.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup child_create child_create + * @{ @ingroup tasks_v2 + */ + +#ifndef CHILD_CREATE_H_ +#define CHILD_CREATE_H_ + +typedef struct child_create_t child_create_t; + +#include +#include +#include +#include + +/** + * Task of type TASK_CHILD_CREATE, established a new CHILD_SA. + * + * This task may be included in the IKE_AUTH message or in a separate + * CREATE_CHILD_SA exchange. + */ +struct child_create_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Use a specific reqid for the CHILD_SA. + * + * When this task is used for rekeying, the same reqid is used + * for the new CHILD_SA. + * + * @param reqid reqid to use + */ + void (*use_reqid) (child_create_t *this, u_int32_t reqid); + + /** + * Get the lower of the two nonces, used for rekey collisions. + * + * @return lower nonce + */ + chunk_t (*get_lower_nonce) (child_create_t *this); + + /** + * Get the CHILD_SA established/establishing by this task. + * + * @return child_sa + */ + child_sa_t* (*get_child) (child_create_t *this); + + /** + * Enforce a specific CHILD_SA config as responder. + * + * @param cfg configuration to enforce, reference gets owned + */ + void (*set_config)(child_create_t *this, child_cfg_t *cfg); +}; + +/** + * Create a new child_create task. + * + * @param ike_sa IKE_SA this task works for + * @param config child_cfg if task initiator, NULL if responder + * @param rekey whether we do a rekey or not + * @param tsi source of triggering packet, or NULL + * @param tsr destination of triggering packet, or NULL + * @return child_create task to handle by the task_manager + */ +child_create_t *child_create_create(ike_sa_t *ike_sa, + child_cfg_t *config, bool rekey, + traffic_selector_t *tsi, traffic_selector_t *tsr); + +#endif /** CHILD_CREATE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c new file mode 100644 index 000000000..644af782c --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2006-2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "child_delete.h" + +#include +#include + + +typedef struct private_child_delete_t private_child_delete_t; + +/** + * Private members of a child_delete_t task. + */ +struct private_child_delete_t { + + /** + * Public methods and task_t interface. + */ + child_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Protocol of CHILD_SA to delete + */ + protocol_id_t protocol; + + /** + * Inbound SPI of CHILD_SA to delete + */ + u_int32_t spi; + + /** + * whether to enforce delete action policy + */ + bool check_delete_action; + + /** + * is this delete exchange following a rekey? + */ + bool rekeyed; + + /** + * CHILD_SA already expired? + */ + bool expired; + + /** + * CHILD_SAs which get deleted + */ + linked_list_t *child_sas; +}; + +/** + * build the delete payloads from the listed child_sas + */ +static void build_payloads(private_child_delete_t *this, message_t *message) +{ + delete_payload_t *ah = NULL, *esp = NULL; + enumerator_t *enumerator; + child_sa_t *child_sa; + + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) + { + protocol_id_t protocol = child_sa->get_protocol(child_sa); + u_int32_t spi = child_sa->get_spi(child_sa, TRUE); + + switch (protocol) + { + case PROTO_ESP: + if (esp == NULL) + { + esp = delete_payload_create(DELETE, PROTO_ESP); + message->add_payload(message, (payload_t*)esp); + } + esp->add_spi(esp, spi); + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); + break; + case PROTO_AH: + if (ah == NULL) + { + ah = delete_payload_create(DELETE, PROTO_AH); + message->add_payload(message, (payload_t*)ah); + } + ah->add_spi(ah, spi); + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); + break; + default: + break; + } + child_sa->set_state(child_sa, CHILD_DELETING); + } + enumerator->destroy(enumerator); +} + +/** + * read in payloads and find the children to delete + */ +static void process_payloads(private_child_delete_t *this, message_t *message) +{ + enumerator_t *payloads, *spis; + payload_t *payload; + delete_payload_t *delete_payload; + u_int32_t spi; + protocol_id_t protocol; + child_sa_t *child_sa; + + payloads = message->create_payload_enumerator(message); + while (payloads->enumerate(payloads, &payload)) + { + if (payload->get_type(payload) == DELETE) + { + delete_payload = (delete_payload_t*)payload; + protocol = delete_payload->get_protocol_id(delete_payload); + if (protocol != PROTO_ESP && protocol != PROTO_AH) + { + continue; + } + spis = delete_payload->create_spi_enumerator(delete_payload); + while (spis->enumerate(spis, &spi)) + { + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, + spi, FALSE); + if (child_sa == NULL) + { + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, " + "but no such SA", protocol_id_names, protocol, ntohl(spi)); + continue; + } + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); + + switch (child_sa->get_state(child_sa)) + { + case CHILD_REKEYING: + this->rekeyed = TRUE; + /* we reply as usual, rekeying will fail */ + break; + case CHILD_DELETING: + /* we don't send back a delete if we initiated ourself */ + if (!this->initiator) + { + this->ike_sa->destroy_child_sa(this->ike_sa, + protocol, spi); + continue; + } + /* fall through */ + case CHILD_INSTALLED: + if (!this->initiator) + { /* reestablish installed children if required */ + this->check_delete_action = TRUE; + } + default: + break; + } + + this->child_sas->insert_last(this->child_sas, child_sa); + } + spis->destroy(spis); + } + } + payloads->destroy(payloads); +} + +/** + * destroy the children listed in this->child_sas, reestablish by policy + */ +static status_t destroy_and_reestablish(private_child_delete_t *this) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + child_cfg_t *child_cfg; + protocol_id_t protocol; + u_int32_t spi; + action_t action; + status_t status = SUCCESS; + + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) + { + /* signal child down event if we are not rekeying */ + if (!this->rekeyed) + { + charon->bus->child_updown(charon->bus, child_sa, FALSE); + } + spi = child_sa->get_spi(child_sa, TRUE); + protocol = child_sa->get_protocol(child_sa); + child_cfg = child_sa->get_config(child_sa); + child_cfg->get_ref(child_cfg); + action = child_sa->get_close_action(child_sa); + this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); + if (this->check_delete_action) + { /* enforce child_cfg policy if deleted passively */ + switch (action) + { + case ACTION_RESTART: + child_cfg->get_ref(child_cfg); + status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0, + NULL, NULL); + break; + case ACTION_ROUTE: + charon->traps->install(charon->traps, + this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg); + break; + default: + break; + } + } + child_cfg->destroy(child_cfg); + if (status != SUCCESS) + { + break; + } + } + enumerator->destroy(enumerator); + return status; +} + +/** + * send closing signals for all CHILD_SAs over the bus + */ +static void log_children(private_child_delete_t *this) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + u_int64_t bytes_in, bytes_out; + + enumerator = this->child_sas->create_enumerator(this->child_sas); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) + { + if (this->expired) + { + DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + else + { + child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); + child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); + + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i " + "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, + ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_child_delete_t *this, message_t *message) +{ + child_sa_t *child_sa; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, + this->spi, TRUE); + if (!child_sa) + { /* check if it is an outbound sa */ + child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, + this->spi, FALSE); + if (!child_sa) + { /* child does not exist anymore */ + return SUCCESS; + } + /* we work only with the inbound SPI */ + this->spi = child_sa->get_spi(child_sa, TRUE); + } + this->child_sas->insert_last(this->child_sas, child_sa); + if (child_sa->get_state(child_sa) == CHILD_REKEYING) + { + this->rekeyed = TRUE; + } + log_children(this); + build_payloads(this, message); + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_child_delete_t *this, message_t *message) +{ + /* flush the list before adding new SAs */ + this->child_sas->destroy(this->child_sas); + this->child_sas = linked_list_create(); + + process_payloads(this, message); + DBG1(DBG_IKE, "CHILD_SA closed"); + return destroy_and_reestablish(this); +} + +METHOD(task_t, process_r, status_t, + private_child_delete_t *this, message_t *message) +{ + process_payloads(this, message); + log_children(this); + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_child_delete_t *this, message_t *message) +{ + /* if we are rekeying, we send an empty informational */ + if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING) + { + build_payloads(this, message); + } + DBG1(DBG_IKE, "CHILD_SA closed"); + return destroy_and_reestablish(this); +} + +METHOD(task_t, get_type, task_type_t, + private_child_delete_t *this) +{ + return TASK_CHILD_DELETE; +} + +METHOD(child_delete_t , get_child, child_sa_t*, + private_child_delete_t *this) +{ + child_sa_t *child_sa = NULL; + this->child_sas->get_first(this->child_sas, (void**)&child_sa); + return child_sa; +} + +METHOD(task_t, migrate, void, + private_child_delete_t *this, ike_sa_t *ike_sa) +{ + this->check_delete_action = FALSE; + this->ike_sa = ike_sa; + + this->child_sas->destroy(this->child_sas); + this->child_sas = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_child_delete_t *this) +{ + this->child_sas->destroy(this->child_sas); + free(this); +} + +/* + * Described in header. + */ +child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi, bool expired) +{ + private_child_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .get_child = _get_child, + }, + .ike_sa = ike_sa, + .child_sas = linked_list_create(), + .protocol = protocol, + .spi = spi, + .expired = expired, + ); + + if (protocol != PROTO_NONE) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + this->initiator = TRUE; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + this->initiator = FALSE; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.h b/src/libcharon/sa/ikev2/tasks/child_delete.h new file mode 100644 index 000000000..1ada0699e --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_delete.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup child_delete child_delete + * @{ @ingroup tasks_v2 + */ + +#ifndef CHILD_DELETE_H_ +#define CHILD_DELETE_H_ + +typedef struct child_delete_t child_delete_t; + +#include +#include +#include +#include + +/** + * Task of type child_delete, delete a CHILD_SA. + */ +struct child_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Get the CHILD_SA to delete by this task. + * + * @return child_sa + */ + child_sa_t* (*get_child) (child_delete_t *this); +}; + +/** + * Create a new child_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder + * @param spi inbound SPI of CHILD_SA to delete + * @param expired TRUE if CHILD_SA already expired + * @return child_delete task to handle by the task_manager + */ +child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi, bool expired); + +#endif /** CHILD_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c new file mode 100644 index 000000000..f8c2ed141 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "child_rekey.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct private_child_rekey_t private_child_rekey_t; + +/** + * Private members of a child_rekey_t task. + */ +struct private_child_rekey_t { + + /** + * Public methods and task_t interface. + */ + child_rekey_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Protocol of CHILD_SA to rekey + */ + protocol_id_t protocol; + + /** + * Inbound SPI of CHILD_SA to rekey + */ + u_int32_t spi; + + /** + * the CHILD_CREATE task which is reused to simplify rekeying + */ + child_create_t *child_create; + + /** + * the CHILD_DELETE task to delete rekeyed CHILD_SA + */ + child_delete_t *child_delete; + + /** + * CHILD_SA which gets rekeyed + */ + child_sa_t *child_sa; + + /** + * colliding task, may be delete or rekey + */ + task_t *collision; + + /** + * Indicate that peer destroyed the redundant child from collision. + * This happens if a peer's delete notification for the redundant + * child gets processed before the rekey job. If so, we must not + * touch the child created in the collision since it points to + * memory already freed. + */ + bool other_child_destroyed; +}; + +/** + * Implementation of task_t.build for initiator, after rekeying + */ +static status_t build_i_delete(private_child_rekey_t *this, message_t *message) +{ + /* update exchange type to INFORMATIONAL for the delete */ + message->set_exchange_type(message, INFORMATIONAL); + + return this->child_delete->task.build(&this->child_delete->task, message); +} + +/** + * Implementation of task_t.process for initiator, after rekeying + */ +static status_t process_i_delete(private_child_rekey_t *this, message_t *message) +{ + return this->child_delete->task.process(&this->child_delete->task, message); +} + +/** + * find a child using the REKEY_SA notify + */ +static void find_child(private_child_rekey_t *this, message_t *message) +{ + notify_payload_t *notify; + protocol_id_t protocol; + u_int32_t spi; + + notify = message->get_notify(message, REKEY_SA); + if (notify) + { + protocol = notify->get_protocol_id(notify); + spi = notify->get_spi(notify); + + if (protocol == PROTO_ESP || protocol == PROTO_AH) + { + this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, + spi, FALSE); + } + } +} + +METHOD(task_t, build_i, status_t, + private_child_rekey_t *this, message_t *message) +{ + notify_payload_t *notify; + u_int32_t reqid; + child_cfg_t *config; + + this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, + this->spi, TRUE); + if (!this->child_sa) + { /* check if it is an outbound CHILD_SA */ + this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, + this->spi, FALSE); + if (!this->child_sa) + { /* CHILD_SA is gone, unable to rekey. As an empty CREATE_CHILD_SA + * exchange is invalid, we fall back to an INFORMATIONAL exchange.*/ + message->set_exchange_type(message, INFORMATIONAL); + return SUCCESS; + } + /* we work only with the inbound SPI */ + this->spi = this->child_sa->get_spi(this->child_sa, TRUE); + } + config = this->child_sa->get_config(this->child_sa); + + /* we just need the rekey notify ... */ + notify = notify_payload_create_from_protocol_and_type(NOTIFY, + this->protocol, REKEY_SA); + notify->set_spi(notify, this->spi); + message->add_payload(message, (payload_t*)notify); + + /* ... our CHILD_CREATE task does the hard work for us. */ + if (!this->child_create) + { + this->child_create = child_create_create(this->ike_sa, + config->get_ref(config), TRUE, NULL, NULL); + } + reqid = this->child_sa->get_reqid(this->child_sa); + this->child_create->use_reqid(this->child_create, reqid); + this->child_create->task.build(&this->child_create->task, message); + + this->child_sa->set_state(this->child_sa, CHILD_REKEYING); + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_child_rekey_t *this, message_t *message) +{ + /* let the CHILD_CREATE task process the message */ + this->child_create->task.process(&this->child_create->task, message); + + find_child(this, message); + + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_child_rekey_t *this, message_t *message) +{ + child_cfg_t *config; + u_int32_t reqid; + + if (this->child_sa == NULL || + this->child_sa->get_state(this->child_sa) == CHILD_DELETING) + { + DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found"); + message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); + return SUCCESS; + } + + /* let the CHILD_CREATE task build the response */ + reqid = this->child_sa->get_reqid(this->child_sa); + this->child_create->use_reqid(this->child_create, reqid); + config = this->child_sa->get_config(this->child_sa); + this->child_create->set_config(this->child_create, config->get_ref(config)); + this->child_create->task.build(&this->child_create->task, message); + + if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + { + /* rekeying failed, reuse old child */ + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + return SUCCESS; + } + + this->child_sa->set_state(this->child_sa, CHILD_REKEYING); + + /* invoke rekey hook */ + charon->bus->child_rekey(charon->bus, this->child_sa, + this->child_create->get_child(this->child_create)); + return SUCCESS; +} + +/** + * Handle a rekey collision + */ +static child_sa_t *handle_collision(private_child_rekey_t *this) +{ + child_sa_t *to_delete; + + if (this->collision->get_type(this->collision) == TASK_CHILD_REKEY) + { + chunk_t this_nonce, other_nonce; + private_child_rekey_t *other = (private_child_rekey_t*)this->collision; + + this_nonce = this->child_create->get_lower_nonce(this->child_create); + other_nonce = other->child_create->get_lower_nonce(other->child_create); + + /* if we have the lower nonce, delete rekeyed SA. If not, delete + * the redundant. */ + if (memcmp(this_nonce.ptr, other_nonce.ptr, + min(this_nonce.len, other_nonce.len)) > 0) + { + child_sa_t *child_sa; + + DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child"); + to_delete = this->child_sa; + /* don't touch child other created, it has already been deleted */ + if (!this->other_child_destroyed) + { + /* disable close action for the redundand child */ + child_sa = other->child_create->get_child(other->child_create); + if (child_sa) + { + child_sa->set_close_action(child_sa, ACTION_NONE); + } + } + } + else + { + DBG1(DBG_IKE, "CHILD_SA rekey collision lost, " + "deleting rekeyed child"); + to_delete = this->child_create->get_child(this->child_create); + } + } + else + { /* CHILD_DELETE */ + child_delete_t *del = (child_delete_t*)this->collision; + + /* we didn't had a chance to compare the nonces, so we delete + * the CHILD_SA the other is not deleting. */ + if (del->get_child(del) != this->child_sa) + { + DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, " + "deleting rekeyed child"); + to_delete = this->child_sa; + } + else + { + DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, " + "deleting redundant child"); + to_delete = this->child_create->get_child(this->child_create); + } + } + return to_delete; +} + +METHOD(task_t, process_i, status_t, + private_child_rekey_t *this, message_t *message) +{ + protocol_id_t protocol; + u_int32_t spi; + child_sa_t *to_delete; + + if (message->get_notify(message, NO_ADDITIONAL_SAS)) + { + DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, " + "starting reauthentication"); + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + lib->processor->queue_job(lib->processor, + (job_t*)rekey_ike_sa_job_create( + this->ike_sa->get_id(this->ike_sa), TRUE)); + return SUCCESS; + } + + if (this->child_create->task.process(&this->child_create->task, + message) == NEED_MORE) + { + /* bad DH group while rekeying, try again */ + this->child_create->task.migrate(&this->child_create->task, this->ike_sa); + return NEED_MORE; + } + if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + { + /* establishing new child failed, reuse old. but not when we + * received a delete in the meantime */ + if (!(this->collision && + this->collision->get_type(this->collision) == TASK_CHILD_DELETE)) + { + job_t *job; + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + + job = (job_t*)rekey_child_sa_job_create( + this->child_sa->get_reqid(this->child_sa), + this->child_sa->get_protocol(this->child_sa), + this->child_sa->get_spi(this->child_sa, TRUE)); + DBG1(DBG_IKE, "CHILD_SA rekeying failed, " + "trying again in %d seconds", retry); + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + lib->scheduler->schedule_job(lib->scheduler, job, retry); + } + return SUCCESS; + } + + /* check for rekey collisions */ + if (this->collision) + { + to_delete = handle_collision(this); + } + else + { + to_delete = this->child_sa; + } + + if (to_delete != this->child_create->get_child(this->child_create)) + { /* invoke rekey hook if rekeying successful */ + charon->bus->child_rekey(charon->bus, this->child_sa, + this->child_create->get_child(this->child_create)); + } + + if (to_delete == NULL) + { + return SUCCESS; + } + spi = to_delete->get_spi(to_delete, TRUE); + protocol = to_delete->get_protocol(to_delete); + + /* rekeying done, delete the obsolete CHILD_SA using a subtask */ + this->child_delete = child_delete_create(this->ike_sa, protocol, spi, FALSE); + this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete; + this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete; + + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_child_rekey_t *this) +{ + return TASK_CHILD_REKEY; +} + +METHOD(child_rekey_t, collide, void, + private_child_rekey_t *this, task_t *other) +{ + /* the task manager only detects exchange collision, but not if + * the collision is for the same child. we check it here. */ + if (other->get_type(other) == TASK_CHILD_REKEY) + { + private_child_rekey_t *rekey = (private_child_rekey_t*)other; + if (rekey->child_sa != this->child_sa) + { + /* not the same child => no collision */ + other->destroy(other); + return; + } + } + else if (other->get_type(other) == TASK_CHILD_DELETE) + { + child_delete_t *del = (child_delete_t*)other; + if (del->get_child(del) == this->child_create->get_child(this->child_create)) + { + /* peer deletes redundant child created in collision */ + this->other_child_destroyed = TRUE; + other->destroy(other); + return; + } + if (del->get_child(del) != this->child_sa) + { + /* not the same child => no collision */ + other->destroy(other); + return; + } + } + else + { + /* any other task is not critical for collisisions, ignore */ + other->destroy(other); + return; + } + DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, + TASK_CHILD_REKEY, task_type_names, other->get_type(other)); + DESTROY_IF(this->collision); + this->collision = other; +} + +METHOD(task_t, migrate, void, + private_child_rekey_t *this, ike_sa_t *ike_sa) +{ + if (this->child_create) + { + this->child_create->task.migrate(&this->child_create->task, ike_sa); + } + if (this->child_delete) + { + this->child_delete->task.migrate(&this->child_delete->task, ike_sa); + } + DESTROY_IF(this->collision); + + this->ike_sa = ike_sa; + this->collision = NULL; +} + +METHOD(task_t, destroy, void, + private_child_rekey_t *this) +{ + if (this->child_create) + { + this->child_create->task.destroy(&this->child_create->task); + } + if (this->child_delete) + { + this->child_delete->task.destroy(&this->child_delete->task); + } + DESTROY_IF(this->collision); + free(this); +} + +/* + * Described in header. + */ +child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi) +{ + private_child_rekey_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .collide = _collide, + }, + .ike_sa = ike_sa, + .protocol = protocol, + .spi = spi, + ); + + if (protocol != PROTO_NONE) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + this->initiator = TRUE; + this->child_create = NULL; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + this->initiator = FALSE; + this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL); + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.h b/src/libcharon/sa/ikev2/tasks/child_rekey.h new file mode 100644 index 000000000..23384653d --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup child_rekey child_rekey + * @{ @ingroup tasks_v2 + */ + +#ifndef CHILD_REKEY_H_ +#define CHILD_REKEY_H_ + +typedef struct child_rekey_t child_rekey_t; + +#include +#include +#include +#include + +/** + * Task of type TASK_CHILD_REKEY, rekey an established CHILD_SA. + */ +struct child_rekey_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Register a rekeying task which collides with this one + * + * If two peers initiate rekeying at the same time, the collision must + * be handled gracefully. The task manager is aware of what exchanges + * are going on and notifies the outgoing task by passing the incoming. + * + * @param other incoming task + */ + void (*collide)(child_rekey_t* this, task_t *other); +}; + +/** + * Create a new TASK_CHILD_REKEY task. + * + * @param ike_sa IKE_SA this task works for + * @param protocol protocol of CHILD_SA to rekey, PROTO_NONE as responder + * @param spi inbound SPI of CHILD_SA to rekey + * @return child_rekey task to handle by the task_manager + */ +child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi); + +#endif /** CHILD_REKEY_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c new file mode 100644 index 000000000..cd94ccd9e --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c @@ -0,0 +1,1110 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details + */ + +#include "ike_auth.h" + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct private_ike_auth_t private_ike_auth_t; + +/** + * Private members of a ike_auth_t task. + */ +struct private_ike_auth_t { + + /** + * Public methods and task_t interface. + */ + ike_auth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Nonce chosen by us in ike_init + */ + chunk_t my_nonce; + + /** + * Nonce chosen by peer in ike_init + */ + chunk_t other_nonce; + + /** + * IKE_SA_INIT message sent by us + */ + packet_t *my_packet; + + /** + * IKE_SA_INIT message sent by peer + */ + packet_t *other_packet; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; + + /** + * currently active authenticator, to authenticate us + */ + authenticator_t *my_auth; + + /** + * currently active authenticator, to authenticate peer + */ + authenticator_t *other_auth; + + /** + * peer_cfg candidates, ordered by priority + */ + linked_list_t *candidates; + + /** + * selected peer config (might change when using multiple authentications) + */ + peer_cfg_t *peer_cfg; + + /** + * have we planned an(other) authentication exchange? + */ + bool do_another_auth; + + /** + * has the peer announced another authentication exchange? + */ + bool expect_another_auth; + + /** + * should we send a AUTHENTICATION_FAILED notify? + */ + bool authentication_failed; + + /** + * received an INITIAL_CONTACT? + */ + bool initial_contact; +}; + +/** + * check if multiple authentication extension is enabled, configuration-wise + */ +static bool multiple_auth_enabled() +{ + return lib->settings->get_bool(lib->settings, + "%s.multiple_authentication", TRUE, charon->name); +} + +/** + * collect the needed information in the IKE_SA_INIT exchange from our message + */ +static status_t collect_my_init_data(private_ike_auth_t *this, + message_t *message) +{ + nonce_payload_t *nonce; + + /* get the nonce that was generated in ike_init */ + nonce = (nonce_payload_t*)message->get_payload(message, NONCE); + if (nonce == NULL) + { + return FAILED; + } + this->my_nonce = nonce->get_nonce(nonce); + + /* pre-generate the message, keep a copy */ + if (this->ike_sa->generate_message(this->ike_sa, message, + &this->my_packet) != SUCCESS) + { + return FAILED; + } + return NEED_MORE; +} + +/** + * collect the needed information in the IKE_SA_INIT exchange from others message + */ +static status_t collect_other_init_data(private_ike_auth_t *this, + message_t *message) +{ + /* we collect the needed information in the IKE_SA_INIT exchange */ + nonce_payload_t *nonce; + + /* get the nonce that was generated in ike_init */ + nonce = (nonce_payload_t*)message->get_payload(message, NONCE); + if (nonce == NULL) + { + return FAILED; + } + this->other_nonce = nonce->get_nonce(nonce); + + /* keep a copy of the received packet */ + this->other_packet = message->get_packet(message); + return NEED_MORE; +} + +/** + * Get and store reserved bytes of id_payload, required for AUTH payload + */ +static void get_reserved_id_bytes(private_ike_auth_t *this, id_payload_t *id) +{ + u_int8_t *byte; + int i; + + for (i = 0; i < countof(this->reserved); i++) + { + byte = payload_get_field(&id->payload_interface, RESERVED_BYTE, i); + if (byte) + { + this->reserved[i] = *byte; + } + } +} + +/** + * Get the next authentication configuration + */ +static auth_cfg_t *get_auth_cfg(private_ike_auth_t *this, bool local) +{ + enumerator_t *e1, *e2; + auth_cfg_t *c1, *c2, *next = NULL; + + /* find an available config not already done */ + e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, local); + while (e1->enumerate(e1, &c1)) + { + bool found = FALSE; + + e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, local); + while (e2->enumerate(e2, &c2)) + { + if (c2->complies(c2, c1, FALSE)) + { + found = TRUE; + break; + } + } + e2->destroy(e2); + if (!found) + { + next = c1; + break; + } + } + e1->destroy(e1); + return next; +} + +/** + * Check if we have should initiate another authentication round + */ +static bool do_another_auth(private_ike_auth_t *this) +{ + bool do_another = FALSE; + enumerator_t *done, *todo; + auth_cfg_t *done_cfg, *todo_cfg; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) + { + return FALSE; + } + + done = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, TRUE); + todo = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, TRUE); + while (todo->enumerate(todo, &todo_cfg)) + { + if (!done->enumerate(done, &done_cfg)) + { + done_cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + } + if (!done_cfg->complies(done_cfg, todo_cfg, FALSE)) + { + do_another = TRUE; + break; + } + } + done->destroy(done); + todo->destroy(todo); + return do_another; +} + +/** + * Get peer configuration candidates from backends + */ +static bool load_cfg_candidates(private_ike_auth_t *this) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + host_t *me, *other; + identification_t *my_id, *other_id; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", + me, my_id, other, other_id); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, my_id, other_id, IKEV2); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + peer_cfg->get_ref(peer_cfg); + if (this->peer_cfg == NULL) + { /* best match */ + this->peer_cfg = peer_cfg; + this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg); + } + else + { + this->candidates->insert_last(this->candidates, peer_cfg); + } + } + enumerator->destroy(enumerator); + if (this->peer_cfg) + { + DBG1(DBG_CFG, "selected peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + return TRUE; + } + DBG1(DBG_CFG, "no matching peer config found"); + return FALSE; +} + +/** + * update the current peer candidate if necessary, using candidates + */ +static bool update_cfg_candidates(private_ike_auth_t *this, bool strict) +{ + do + { + if (this->peer_cfg) + { + bool complies = TRUE; + enumerator_t *e1, *e2, *tmp; + auth_cfg_t *c1, *c2; + + e1 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE); + e2 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE); + + if (strict) + { /* swap lists in strict mode: all configured rounds must be + * fulfilled. If !strict, we check only the rounds done so far. */ + tmp = e1; + e1 = e2; + e2 = tmp; + } + while (e1->enumerate(e1, &c1)) + { + /* check if done authentications comply to configured ones */ + if ((!e2->enumerate(e2, &c2)) || + (!strict && !c1->complies(c1, c2, TRUE)) || + (strict && !c2->complies(c2, c1, TRUE))) + { + complies = FALSE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + if (complies) + { + break; + } + DBG1(DBG_CFG, "selected peer config '%s' inacceptable", + this->peer_cfg->get_name(this->peer_cfg)); + this->peer_cfg->destroy(this->peer_cfg); + } + if (this->candidates->remove_first(this->candidates, + (void**)&this->peer_cfg) != SUCCESS) + { + DBG1(DBG_CFG, "no alternative config found"); + this->peer_cfg = NULL; + } + else + { + DBG1(DBG_CFG, "switching to peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + } + } + while (this->peer_cfg); + + return this->peer_cfg != NULL; +} + +METHOD(task_t, build_i, status_t, + private_ike_auth_t *this, message_t *message) +{ + auth_cfg_t *cfg; + + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return collect_my_init_data(this, message); + } + + if (this->peer_cfg == NULL) + { + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + } + + if (message->get_message_id(message) == 1) + { /* in the first IKE_AUTH ... */ + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) + { /* indicate support for multiple authentication */ + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, + chunk_empty); + } + /* indicate support for EAP-only authentication */ + message->add_notify(message, FALSE, EAP_ONLY_AUTHENTICATION, + chunk_empty); + } + + if (!this->do_another_auth && !this->my_auth) + { /* we have done our rounds */ + return NEED_MORE; + } + + /* check if an authenticator is in progress */ + if (this->my_auth == NULL) + { + identification_t *idi, *idr = NULL; + id_payload_t *id_payload; + + /* clean up authentication config from a previous round */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + + /* add (optional) IDr */ + cfg = get_auth_cfg(this, FALSE); + if (cfg) + { + idr = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!cfg->get(cfg, AUTH_RULE_IDENTITY_LOOSE) && idr && + !idr->contains_wildcards(idr)) + { + this->ike_sa->set_other_id(this->ike_sa, idr->clone(idr)); + id_payload = id_payload_create_from_identification( + ID_RESPONDER, idr); + message->add_payload(message, (payload_t*)id_payload); + } + } + /* add IDi */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + idi = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!idi || idi->get_type(idi) == ID_ANY) + { /* ID_ANY is invalid as IDi, use local IP address instead */ + host_t *me; + + DBG1(DBG_CFG, "no IDi configured, fall back on IP address"); + me = this->ike_sa->get_my_host(this->ike_sa); + idi = identification_create_from_sockaddr(me->get_sockaddr(me)); + cfg->add(cfg, AUTH_RULE_IDENTITY, idi); + } + this->ike_sa->set_my_id(this->ike_sa, idi->clone(idi)); + id_payload = id_payload_create_from_identification(ID_INITIATOR, idi); + get_reserved_id_bytes(this, id_payload); + message->add_payload(message, (payload_t*)id_payload); + + if (idr && message->get_message_id(message) == 1 && + this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO && + this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NEVER) + { + host_t *host; + + host = this->ike_sa->get_other_host(this->ike_sa); + if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager, + idi, idr, host->get_family(host))) + { + message->add_notify(message, FALSE, INITIAL_CONTACT, chunk_empty); + } + } + + /* build authentication data */ + this->my_auth = authenticator_create_builder(this->ike_sa, cfg, + this->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_packet), + this->reserved); + if (!this->my_auth) + { + return FAILED; + } + } + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + /* authentication step complete, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), TRUE); + this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + return FAILED; + } + + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + if (message->get_payload(message, AUTHENTICATION)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + } + else + { + this->do_another_auth = FALSE; + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_auth_t *this, message_t *message) +{ + auth_cfg_t *cfg, *cand; + id_payload_t *id_payload; + identification_t *id; + + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + return collect_other_init_data(this, message); + } + + if (this->my_auth == NULL && this->do_another_auth) + { + /* handle (optional) IDr payload, apply proposed identity */ + id_payload = (id_payload_t*)message->get_payload(message, ID_RESPONDER); + if (id_payload) + { + id = id_payload->get_identification(id_payload); + } + else + { + id = identification_create_from_encoding(ID_ANY, chunk_empty); + } + this->ike_sa->set_my_id(this->ike_sa, id); + } + + if (!this->expect_another_auth) + { + return NEED_MORE; + } + + if (message->get_message_id(message) == 1) + { /* check for extensions in the first IKE_AUTH */ + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED)) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } + if (message->get_notify(message, EAP_ONLY_AUTHENTICATION)) + { + this->ike_sa->enable_extension(this->ike_sa, + EXT_EAP_ONLY_AUTHENTICATION); + } + } + + if (this->other_auth == NULL) + { + /* handle IDi payload */ + id_payload = (id_payload_t*)message->get_payload(message, ID_INITIATOR); + if (!id_payload) + { + DBG1(DBG_IKE, "IDi payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + get_reserved_id_bytes(this, id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + if (this->peer_cfg == NULL) + { + if (!load_cfg_candidates(this)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + if (message->get_payload(message, AUTHENTICATION) == NULL) + { /* before authenticating with EAP, we need a EAP config */ + cand = get_auth_cfg(this, FALSE); + while (!cand || ( + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK && + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0)) + { /* peer requested EAP, but current config does not match */ + DBG1(DBG_IKE, "peer requested EAP, config inacceptable"); + this->peer_cfg->destroy(this->peer_cfg); + this->peer_cfg = NULL; + if (!update_cfg_candidates(this, FALSE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + cand = get_auth_cfg(this, FALSE); + } + /* copy over the EAP specific rules for authentication */ + cfg->add(cfg, AUTH_RULE_EAP_TYPE, + cand->get(cand, AUTH_RULE_EAP_TYPE)); + cfg->add(cfg, AUTH_RULE_EAP_VENDOR, + cand->get(cand, AUTH_RULE_EAP_VENDOR)); + id = (identification_t*)cand->get(cand, AUTH_RULE_EAP_IDENTITY); + if (id) + { + cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); + } + id = (identification_t*)cand->get(cand, AUTH_RULE_AAA_IDENTITY); + if (id) + { + cfg->add(cfg, AUTH_RULE_AAA_IDENTITY, id->clone(id)); + } + } + + /* verify authentication data */ + this->other_auth = authenticator_create_verifier(this->ike_sa, + message, this->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_packet), + this->reserved); + if (!this->other_auth) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + switch (this->other_auth->process(this->other_auth, message)) + { + case SUCCESS: + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + break; + case NEED_MORE: + if (message->get_payload(message, AUTHENTICATION)) + { /* AUTH verification successful, but another build() needed */ + break; + } + return NEED_MORE; + default: + this->authentication_failed = TRUE; + return NEED_MORE; + } + + /* If authenticated (with non-EAP) and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. */ + if (message->get_message_id(message) == 1 && + message->get_notify(message, INITIAL_CONTACT)) + { + this->initial_contact = TRUE; + } + + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "authorization hook forbids IKE_SA, cancelling"); + this->authentication_failed = TRUE; + return NEED_MORE; + } + + /* store authentication information */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); + + if (!update_cfg_candidates(this, FALSE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) + { + this->expect_another_auth = FALSE; + if (!update_cfg_candidates(this, TRUE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_auth_t *this, message_t *message) +{ + auth_cfg_t *cfg; + + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + if (multiple_auth_enabled()) + { + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, + chunk_empty); + } + return collect_my_init_data(this, message); + } + + if (this->authentication_failed || this->peer_cfg == NULL) + { + goto peer_auth_failed; + } + + if (this->my_auth == NULL && this->do_another_auth) + { + identification_t *id, *id_cfg; + id_payload_t *id_payload; + + /* add IDr */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + + id_cfg = cfg->get(cfg, AUTH_RULE_IDENTITY); + id = this->ike_sa->get_my_id(this->ike_sa); + if (id->get_type(id) == ID_ANY) + { /* no IDr received, apply configured ID */ + if (!id_cfg || id_cfg->contains_wildcards(id_cfg)) + { /* no ID configured, use local IP address */ + host_t *me; + + DBG1(DBG_CFG, "no IDr configured, fall back on IP address"); + me = this->ike_sa->get_my_host(this->ike_sa); + id_cfg = identification_create_from_sockaddr( + me->get_sockaddr(me)); + cfg->add(cfg, AUTH_RULE_IDENTITY, id_cfg); + } + this->ike_sa->set_my_id(this->ike_sa, id_cfg->clone(id_cfg)); + id = id_cfg; + } + else + { /* IDr received, check if it matches configuration */ + if (id_cfg && !id->matches(id, id_cfg)) + { + DBG1(DBG_CFG, "received IDr %Y, but require %Y", id, id_cfg); + goto peer_auth_failed; + } + } + + id_payload = id_payload_create_from_identification(ID_RESPONDER, id); + get_reserved_id_bytes(this, id_payload); + message->add_payload(message, (payload_t*)id_payload); + + if (this->initial_contact) + { + charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, TRUE); + this->initial_contact = FALSE; + } + + if ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS) == AUTH_CLASS_EAP) + { /* EAP-only authentication */ + if (!this->ike_sa->supports_extension(this->ike_sa, + EXT_EAP_ONLY_AUTHENTICATION)) + { + DBG1(DBG_IKE, "configured EAP-only authentication, but peer " + "does not support it"); + goto peer_auth_failed; + } + } + else + { + /* build authentication data */ + this->my_auth = authenticator_create_builder(this->ike_sa, cfg, + this->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_packet), + this->reserved); + if (!this->my_auth) + { + goto peer_auth_failed; + } + } + } + + if (this->other_auth) + { + switch (this->other_auth->build(this->other_auth, message)) + { + case SUCCESS: + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + break; + case NEED_MORE: + break; + default: + if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + { /* skip AUTHENTICATION_FAILED if we have EAP_FAILURE */ + goto peer_auth_failed_no_notify; + } + goto peer_auth_failed; + } + } + if (this->my_auth) + { + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + } + + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + else + { + this->do_another_auth = FALSE; + } + if (!this->do_another_auth && !this->expect_another_auth) + { + if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, FALSE)) + { + DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + goto peer_auth_failed; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; + } + return NEED_MORE; + +peer_auth_failed: + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); +peer_auth_failed_no_notify: + charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_ike_auth_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *cfg; + bool mutual_eap = FALSE; + + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED) && + multiple_auth_enabled()) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } + return collect_other_init_data(this, message); + } + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + notify_type_t type = notify->get_notify_type(notify); + + switch (type) + { + case NO_PROPOSAL_CHOSEN: + case SINGLE_PAIR_REQUIRED: + case NO_ADDITIONAL_SAS: + case INTERNAL_ADDRESS_FAILURE: + case FAILED_CP_REQUIRED: + case TS_UNACCEPTABLE: + case INVALID_SELECTORS: + /* these are errors, but are not critical as only the + * CHILD_SA won't get build, but IKE_SA establishes anyway */ + break; + case MOBIKE_SUPPORTED: + case ADDITIONAL_IP4_ADDRESS: + case ADDITIONAL_IP6_ADDRESS: + /* handled in ike_mobike task */ + break; + case AUTH_LIFETIME: + /* handled in ike_auth_lifetime task */ + break; + case ME_ENDPOINT: + /* handled in ike_me task */ + break; + default: + { + if (type <= 16383) + { + DBG1(DBG_IKE, "received %N notify error", + notify_type_names, type); + enumerator->destroy(enumerator); + return FAILED; + } + DBG2(DBG_IKE, "received %N notify", + notify_type_names, type); + break; + } + } + } + } + enumerator->destroy(enumerator); + + if (this->expect_another_auth) + { + if (this->other_auth == NULL) + { + id_payload_t *id_payload; + identification_t *id; + + /* handle IDr payload */ + id_payload = (id_payload_t*)message->get_payload(message, + ID_RESPONDER); + if (!id_payload) + { + DBG1(DBG_IKE, "IDr payload missing"); + goto peer_auth_failed; + } + id = id_payload->get_identification(id_payload); + get_reserved_id_bytes(this, id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + if (message->get_payload(message, AUTHENTICATION)) + { + /* verify authentication data */ + this->other_auth = authenticator_create_verifier(this->ike_sa, + message, this->other_nonce, this->my_nonce, + this->other_packet->get_data(this->other_packet), + this->my_packet->get_data(this->my_packet), + this->reserved); + if (!this->other_auth) + { + goto peer_auth_failed; + } + } + else + { + /* responder omitted AUTH payload, indicating EAP-only */ + mutual_eap = TRUE; + } + } + if (this->other_auth) + { + switch (this->other_auth->process(this->other_auth, message)) + { + case SUCCESS: + break; + case NEED_MORE: + return NEED_MORE; + default: + goto peer_auth_failed; + } + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + } + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "authorization forbids IKE_SA, cancelling"); + goto peer_auth_failed; + } + + /* store authentication information, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); + } + + if (this->my_auth) + { + switch (this->my_auth->process(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + this->do_another_auth = do_another_auth(this); + break; + case NEED_MORE: + break; + default: + return FAILED; + } + } + if (mutual_eap) + { + if (!this->my_auth || !this->my_auth->is_mutual(this->my_auth)) + { + DBG1(DBG_IKE, "do not allow non-mutual EAP-only authentication"); + goto peer_auth_failed; + } + DBG1(DBG_IKE, "allow mutual EAP-only authentication"); + } + + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) + { + this->expect_another_auth = FALSE; + } + if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth) + { + if (!update_cfg_candidates(this, TRUE)) + { + goto peer_auth_failed; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, " + "cancelling"); + goto peer_auth_failed; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; + } + return NEED_MORE; + +peer_auth_failed: + charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_auth_t *this) +{ + return TASK_IKE_AUTH; +} + +METHOD(task_t, migrate, void, + private_ike_auth_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->my_nonce); + chunk_free(&this->other_nonce); + DESTROY_IF(this->my_packet); + DESTROY_IF(this->other_packet); + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); + + this->my_packet = NULL; + this->other_packet = NULL; + this->ike_sa = ike_sa; + this->peer_cfg = NULL; + this->my_auth = NULL; + this->other_auth = NULL; + this->do_another_auth = TRUE; + this->expect_another_auth = TRUE; + this->authentication_failed = FALSE; + this->candidates = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_ike_auth_t *this) +{ + chunk_free(&this->my_nonce); + chunk_free(&this->other_nonce); + DESTROY_IF(this->my_packet); + DESTROY_IF(this->other_packet); + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + DESTROY_IF(this->peer_cfg); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); + free(this); +} + +/* + * Described in header. + */ +ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_auth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .build = _build_r, + .process = _process_r, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .candidates = linked_list_create(), + .do_another_auth = TRUE, + .expect_another_auth = TRUE, + ); + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.h b/src/libcharon/sa/ikev2/tasks/ike_auth.h new file mode 100644 index 000000000..ca864a710 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_auth ike_auth + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_AUTH_H_ +#define IKE_AUTH_H_ + +typedef struct ike_auth_t ike_auth_t; + +#include +#include +#include + +/** + * Task of type ike_auth, authenticates an IKE_SA using authenticators. + * + * The ike_auth task authenticates the IKE_SA using the IKE_AUTH + * exchange. It processes and build IDi and IDr payloads and also + * handles AUTH payloads. The AUTH payloads are passed to authenticator_t's, + * which do the actual authentication process. If the ike_auth task is used + * with EAP authentication, it stays alive over multiple exchanges until + * EAP has completed. + */ +struct ike_auth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new task of type TASK_IKE_AUTH. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the initiator of an exchange + * @return ike_auth task to handle by the task_manager + */ +ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_AUTH_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c new file mode 100644 index 000000000..a7d162e68 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_auth_lifetime.h" + +#include + +#include +#include + + +typedef struct private_ike_auth_lifetime_t private_ike_auth_lifetime_t; + +/** + * Private members of a ike_auth_lifetime_t task. + */ +struct private_ike_auth_lifetime_t { + + /** + * Public methods and task_t interface. + */ + ike_auth_lifetime_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; +}; + +/** + * add the AUTH_LIFETIME notify to the message + */ +static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *message) +{ + chunk_t chunk; + u_int32_t lifetime; + + lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH); + if (lifetime) + { + lifetime -= time_monotonic(NULL); + chunk = chunk_from_thing(lifetime); + *(u_int32_t*)chunk.ptr = htonl(lifetime); + message->add_notify(message, FALSE, AUTH_LIFETIME, chunk); + } +} + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message) +{ + notify_payload_t *notify; + chunk_t data; + u_int32_t lifetime; + + notify = message->get_notify(message, AUTH_LIFETIME); + if (notify) + { + data = notify->get_notification_data(notify); + lifetime = ntohl(*(u_int32_t*)data.ptr); + this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime); + } +} + +METHOD(task_t, build_i, status_t, + private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == INFORMATIONAL) + { + add_auth_lifetime(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + add_auth_lifetime(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_auth_lifetime_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + process_payloads(this, message); + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_auth_lifetime_t *this) +{ + return TASK_IKE_AUTH_LIFETIME; +} + +METHOD(task_t, migrate, void, + private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_auth_lifetime_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_auth_lifetime_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h new file mode 100644 index 000000000..4d5087ff5 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_auth_lifetime ike_auth_lifetime + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_AUTH_LIFETIME_H_ +#define IKE_AUTH_LIFETIME_H_ + +typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; + +#include +#include +#include + +/** + * Task of type TASK_IKE_AUTH_LIFETIME, implements RFC4478. + * + * This task exchanges lifetimes for IKE_AUTH to force a client to + * reauthenticate before the responders lifetime reaches the limit. + */ +struct ike_auth_lifetime_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new TASK_IKE_AUTH_LIFETIME task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if taks is initiated by us + * @return ike_auth_lifetime task to handle by the task_manager + */ +ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_AUTH_LIFETIME_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_post.c b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c new file mode 100644 index 000000000..a93e5137e --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_cert_post.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_post_t private_ike_cert_post_t; + +/** + * Private members of a ike_cert_post_t task. + */ +struct private_ike_cert_post_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_post_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; +}; + +/** + * Generates the cert payload, if possible with "Hash and URL" + */ +static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, + certificate_t *cert) +{ + hasher_t *hasher; + identification_t *id; + chunk_t hash, encoded ; + enumerator_t *enumerator; + char *url; + cert_payload_t *payload = NULL; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) + { + return cert_payload_create_from_cert(CERTIFICATE, cert); + } + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); + return cert_payload_create_from_cert(CERTIFICATE, cert); + } + + if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) + { + DBG1(DBG_IKE, "encoding certificate for cert payload failed"); + hasher->destroy(hasher); + return NULL; + } + if (!hasher->allocate_hash(hasher, encoded, &hash)) + { + hasher->destroy(hasher); + chunk_free(&encoded); + return cert_payload_create_from_cert(CERTIFICATE, cert); + } + chunk_free(&encoded); + hasher->destroy(hasher); + id = identification_create_from_encoding(ID_KEY_ID, hash); + + enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); + if (enumerator->enumerate(enumerator, &url)) + { + payload = cert_payload_create_from_hash_and_url(hash, url); + DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); + } + else + { + payload = cert_payload_create_from_cert(CERTIFICATE, cert); + } + enumerator->destroy(enumerator); + chunk_free(&hash); + id->destroy(id); + return payload; +} + +/** + * add certificates to message + */ +static void build_certs(private_ike_cert_post_t *this, message_t *message) +{ + peer_cfg_t *peer_cfg; + auth_payload_t *payload; + + payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK) + { /* no CERT payload for EAP/PSK */ + return; + } + + switch (peer_cfg->get_cert_policy(peer_cfg)) + { + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: + { + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_rule_t type; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + + /* get subject cert first, then issuing certificates */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!cert) + { + break; + } + payload = build_cert_payload(this, cert); + if (!payload) + { + break; + } + DBG1(DBG_IKE, "sending end entity cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &cert)) + { + if (type == AUTH_RULE_IM_CERT) + { + payload = cert_payload_create_from_cert(CERTIFICATE, cert); + if (payload) + { + DBG1(DBG_IKE, "sending issuer cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + } + } + } + enumerator->destroy(enumerator); + } + } +} + +METHOD(task_t, build_i, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + build_certs(this, message); + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + build_certs(this, message); + + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with certs */ + return NEED_MORE; + } + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with CERTS */ + return NEED_MORE; + } + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_cert_post_t *this) +{ + return TASK_IKE_CERT_POST; +} + +METHOD(task_t, migrate, void, + private_ike_cert_post_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_cert_post_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_post_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_post.h b/src/libcharon/sa/ikev2/tasks/ike_cert_post.h new file mode 100644 index 000000000..34606b1e8 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_cert_post ike_cert_post + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_CERT_POST_H_ +#define IKE_CERT_POST_H_ + +typedef struct ike_cert_post_t ike_cert_post_t; + +#include +#include +#include + +/** + * Task of type ike_cert_post, certificate processing after authentication. + */ +struct ike_cert_post_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_post task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_cert_post task to handle by the task_manager + */ +ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_CERT_POST_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c new file mode 100644 index 000000000..60e878777 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c @@ -0,0 +1,529 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_cert_pre.h" + +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_pre_t private_ike_cert_pre_t; + +/** + * Private members of a ike_cert_pre_t task. + */ +struct private_ike_cert_pre_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_pre_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Do we accept HTTP certificate lookup requests + */ + bool do_http_lookup; + + /** + * whether this is the final authentication round + */ + bool final; +}; + +/** + * read certificate requests + */ +static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case CERTIFICATE_REQUEST: + { + certreq_payload_t *certreq = (certreq_payload_t*)payload; + enumerator_t *enumerator; + u_int unknown = 0; + chunk_t keyid; + + this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); + + if (certreq->get_cert_type(certreq) != CERT_X509) + { + DBG1(DBG_IKE, "cert payload %N not supported - ignored", + certificate_type_names, certreq->get_cert_type(certreq)); + break; + } + enumerator = certreq->create_keyid_enumerator(certreq); + while (enumerator->enumerate(enumerator, &keyid)) + { + identification_t *id; + certificate_t *cert; + + id = identification_create_from_encoding(ID_KEY_ID, keyid); + cert = lib->credmgr->get_cert(lib->credmgr, + CERT_X509, KEY_ANY, id, TRUE); + if (cert) + { + DBG1(DBG_IKE, "received cert request for \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_RULE_CA_CERT, cert); + } + else + { + DBG2(DBG_IKE, "received cert request for unknown ca " + "with keyid %Y", id); + unknown++; + } + id->destroy(id); + } + enumerator->destroy(enumerator); + if (unknown) + { + DBG1(DBG_IKE, "received %u cert requests for an unknown ca", + unknown); + } + break; + } + case NOTIFY: + { + notify_payload_t *notify = (notify_payload_t*)payload; + + /* we only handle one type of notify here */ + if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL); + } + break; + } + default: + /* ignore other payloads here, these are handled elsewhere */ + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * tries to extract a certificate from the cert payload or the credential + * manager (based on the hash of a "Hash and URL" encoded cert). + * Note: the returned certificate (if any) has to be destroyed + */ +static certificate_t *try_get_cert(cert_payload_t *cert_payload) +{ + certificate_t *cert = NULL; + + switch (cert_payload->get_cert_encoding(cert_payload)) + { + case ENC_X509_SIGNATURE: + { + cert = cert_payload->get_cert(cert_payload); + break; + } + case ENC_X509_HASH_AND_URL: + { + identification_t *id; + chunk_t hash = cert_payload->get_hash(cert_payload); + if (!hash.ptr) + { + /* invalid "Hash and URL" data (logged elsewhere) */ + break; + } + id = identification_create_from_encoding(ID_KEY_ID, hash); + cert = lib->credmgr->get_cert(lib->credmgr, + CERT_X509, KEY_ANY, id, FALSE); + id->destroy(id); + break; + } + default: + { + break; + } + } + return cert; +} + +/** + * import certificates + */ +static void process_certs(private_ike_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + bool first = TRUE; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CERTIFICATE) + { + cert_payload_t *cert_payload; + cert_encoding_t encoding; + certificate_t *cert; + char *url; + + cert_payload = (cert_payload_t*)payload; + encoding = cert_payload->get_cert_encoding(cert_payload); + + switch (encoding) + { + case ENC_X509_HASH_AND_URL: + { + if (!this->do_http_lookup) + { + DBG1(DBG_IKE, "received hash-and-url encoded cert, but" + " we don't accept them, ignore"); + break; + } + /* FALL */ + } + case ENC_X509_SIGNATURE: + { + cert = try_get_cert(cert_payload); + if (cert) + { + if (first) + { /* the first is an end entity certificate */ + DBG1(DBG_IKE, "received end entity cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); + first = FALSE; + } + else + { + DBG1(DBG_IKE, "received issuer cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_IM_CERT, cert); + } + } + else if (encoding == ENC_X509_HASH_AND_URL) + { + /* we fetch the certificate not yet, but only if + * it is really needed during authentication */ + url = cert_payload->get_url(cert_payload); + if (!url) + { + DBG1(DBG_IKE, "received invalid hash-and-url " + "encoded cert, ignore"); + break; + } + url = strdup(url); + if (first) + { /* first URL is for an end entity certificate */ + DBG1(DBG_IKE, "received hash-and-url for end" + " entity cert \"%s\"", url); + auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url); + first = FALSE; + } + else + { + DBG1(DBG_IKE, "received hash-and-url for issuer" + " cert \"%s\"", url); + auth->add(auth, AUTH_HELPER_IM_HASH_URL, url); + } + } + break; + } + case ENC_CRL: + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + DBG1(DBG_IKE, "received CRL \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert); + } + break; + case ENC_PKCS7_WRAPPED_X509: + case ENC_PGP: + case ENC_DNS_SIGNED_KEY: + case ENC_KERBEROS_TOKEN: + case ENC_ARL: + case ENC_SPKI: + case ENC_X509_ATTRIBUTE: + case ENC_RAW_RSA_KEY: + case ENC_X509_HASH_AND_URL_BUNDLE: + case ENC_OCSP_CONTENT: + default: + DBG1(DBG_ENC, "certificate encoding %N not supported", + cert_encoding_names, encoding); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * add the keyid of a certificate to the certificate request payload + */ +static void add_certreq(certreq_payload_t **req, certificate_t *cert) +{ + switch (cert->get_type(cert)) + { + case CERT_X509: + { + public_key_t *public; + chunk_t keyid; + x509_t *x509 = (x509_t*)cert; + + if (!(x509->get_flags(x509) & X509_CA)) + { /* no CA cert, skip */ + break; + } + public = cert->get_public_key(cert); + if (!public) + { + break; + } + if (*req == NULL) + { + *req = certreq_payload_create_type(CERT_X509); + } + if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) + { + (*req)->add_keyid(*req, keyid); + DBG1(DBG_IKE, "sending cert request for \"%Y\"", + cert->get_subject(cert)); + } + public->destroy(public); + break; + } + default: + break; + } +} + +/** + * add a auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) +{ + enumerator_t *enumerator; + auth_rule_t type; + void *value; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTH_RULE_CA_CERT: + add_certreq(req, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * build certificate requests + */ +static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + certificate_t *cert; + auth_cfg_t *auth; + certreq_payload_t *req = NULL; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + if (!ike_cfg->send_certreq(ike_cfg)) + { + return; + } + + /* check if we require a specific CA for that peer */ + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + while (enumerator->enumerate(enumerator, &auth)) + { + add_certreqs(&req, auth); + } + enumerator->destroy(enumerator); + } + + if (!req) + { + /* otherwise add all trusted CA certificates */ + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_ANY, KEY_ANY, NULL, TRUE); + while (enumerator->enumerate(enumerator, &cert)) + { + add_certreq(&req, cert); + } + enumerator->destroy(enumerator); + } + + if (req) + { + message->add_payload(message, (payload_t*)req); + + if (lib->settings->get_bool(lib->settings, + "%s.hash_and_url", FALSE, charon->name)) + { + message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, + chunk_empty); + this->do_http_lookup = TRUE; + } + } +} + +/** + * Check if this is the final authentication round + */ +static bool final_auth(message_t *message) +{ + /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */ + if (message->get_payload(message, AUTHENTICATION) == NULL) + { + return FALSE; + } + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS)) + { + return FALSE; + } + return TRUE; +} + +METHOD(task_t, build_i, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_message_id(message) == 1) + { /* initiator sends CERTREQs in first IKE_AUTH */ + build_certreqs(this, message); + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) != IKE_SA_INIT) + { /* handle certreqs/certs in any IKE_AUTH, just in case */ + process_certreqs(this, message); + process_certs(this, message); + } + this->final = final_auth(message); + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + build_certreqs(this, message); + } + if (this->final) + { + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_certreqs(this, message); + } + process_certs(this, message); + + if (final_auth(message)) + { + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_cert_pre_t *this) +{ + return TASK_IKE_CERT_PRE; +} + +METHOD(task_t, migrate, void, + private_ike_cert_pre_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_cert_pre_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_pre_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h new file mode 100644 index 000000000..ac1a85c29 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2007-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_cert_pre ike_cert_pre + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_CERT_PRE_H_ +#define IKE_CERT_PRE_H_ + +typedef struct ike_cert_pre_t ike_cert_pre_t; + +#include +#include +#include + +/** + * Task of type ike_cert_post, certificate processing before authentication. + */ +struct ike_cert_pre_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_pre task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_cert_pre task to handle by the task_manager + */ +ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_CERT_PRE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_config.c b/src/libcharon/sa/ikev2/tasks/ike_config.c new file mode 100644 index 000000000..c44f0452c --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_config.c @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2007 Martin Willi + * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_config.h" + +#include +#include +#include + +typedef struct private_ike_config_t private_ike_config_t; + +/** + * Private members of a ike_config_t task. + */ +struct private_ike_config_t { + + /** + * Public methods and task_t interface. + */ + ike_config_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Received list of virtual IPs, host_t* + */ + linked_list_t *vips; + + /** + * list of attributes requested and its handler, entry_t + */ + linked_list_t *requested; +}; + +/** + * Entry for a requested attribute and the requesting handler + */ +typedef struct { + /** attribute requested */ + configuration_attribute_type_t type; + /** handler requesting this attribute */ + attribute_handler_t *handler; +} entry_t; + +/** + * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip + */ +static configuration_attribute_t *build_vip(host_t *vip) +{ + configuration_attribute_type_t type; + chunk_t chunk, prefix; + + if (vip->get_family(vip) == AF_INET) + { + type = INTERNAL_IP4_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + chunk = vip->get_address(vip); + } + } + else + { + type = INTERNAL_IP6_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + prefix = chunk_alloca(1); + *prefix.ptr = 64; + chunk = vip->get_address(vip); + chunk = chunk_cata("cc", chunk, prefix); + } + } + return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, chunk); +} + +/** + * Handle a received attribute as initiator + */ +static void handle_attribute(private_ike_config_t *this, + configuration_attribute_t *ca) +{ + attribute_handler_t *handler = NULL; + enumerator_t *enumerator; + entry_t *entry; + + /* find the handler which requested this attribute */ + enumerator = this->requested->create_enumerator(this->requested); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->type == ca->get_type(ca)) + { + handler = entry->handler; + this->requested->remove_at(this->requested, enumerator); + free(entry); + break; + } + } + enumerator->destroy(enumerator); + + /* and pass it to the handle function */ + handler = hydra->attributes->handle(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), handler, + ca->get_type(ca), ca->get_chunk(ca)); + if (handler) + { + this->ike_sa->add_configuration_attribute(this->ike_sa, + handler, ca->get_type(ca), ca->get_chunk(ca)); + } +} + +/** + * process a single configuration attribute + */ +static void process_attribute(private_ike_config_t *this, + configuration_attribute_t *ca) +{ + host_t *ip; + chunk_t addr; + int family = AF_INET6; + + switch (ca->get_type(ca)) + { + case INTERNAL_IP4_ADDRESS: + family = AF_INET; + /* fall */ + case INTERNAL_IP6_ADDRESS: + { + addr = ca->get_chunk(ca); + if (addr.len == 0) + { + ip = host_create_any(family); + } + else + { + /* skip prefix byte in IPv6 payload*/ + if (family == AF_INET6) + { + addr.len--; + } + ip = host_create_from_chunk(family, addr, 0); + } + if (ip) + { + this->vips->insert_last(this->vips, ip); + } + break; + } + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + /* assume it's a Windows client if we see proprietary attributes */ + this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS); + /* fall */ + default: + { + if (this->initiator) + { + handle_attribute(this, ca); + } + } + } +} + +/** + * Scan for configuration payloads and attributes + */ +static void process_payloads(private_ike_config_t *this, message_t *message) +{ + enumerator_t *enumerator, *attributes; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CONFIGURATION) + { + cp_payload_t *cp = (cp_payload_t*)payload; + configuration_attribute_t *ca; + + switch (cp->get_type(cp)) + { + case CFG_REQUEST: + case CFG_REPLY: + { + attributes = cp->create_attribute_enumerator(cp); + while (attributes->enumerate(attributes, &ca)) + { + DBG2(DBG_IKE, "processing %N attribute", + configuration_attribute_type_names, ca->get_type(ca)); + process_attribute(this, ca); + } + attributes->destroy(attributes); + break; + } + default: + DBG1(DBG_IKE, "ignoring %N config payload", + config_type_names, cp->get_type(cp)); + break; + } + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_ike_config_t *this, message_t *message) +{ + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ + cp_payload_t *cp = NULL; + enumerator_t *enumerator; + attribute_handler_t *handler; + peer_cfg_t *config; + configuration_attribute_type_t type; + chunk_t data; + linked_list_t *vips; + host_t *host; + + vips = linked_list_create(); + + /* reuse virtual IP if we already have one */ + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, + TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + + if (vips->get_count(vips) == 0) + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + enumerator = config->create_virtual_ip_enumerator(config); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + } + + if (vips->get_count(vips)) + { + cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST); + enumerator = vips->create_enumerator(vips); + while (enumerator->enumerate(enumerator, &host)) + { + cp->add_attribute(cp, build_vip(host)); + } + enumerator->destroy(enumerator); + } + + enumerator = hydra->attributes->create_initiator_enumerator( + hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), vips); + while (enumerator->enumerate(enumerator, &handler, &type, &data)) + { + configuration_attribute_t *ca; + entry_t *entry; + + /* create configuration attribute */ + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, data); + if (!cp) + { + cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST); + } + cp->add_attribute(cp, ca); + + /* save handler along with requested type */ + entry = malloc_thing(entry_t); + entry->type = type; + entry->handler = handler; + + this->requested->insert_last(this->requested, entry); + } + enumerator->destroy(enumerator); + + vips->destroy(vips); + + if (cp) + { + message->add_payload(message, (payload_t*)cp); + } + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_config_t *this, message_t *message) +{ + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ + process_payloads(this, message); + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_config_t *this, message_t *message) +{ + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + cp_payload_t *cp = NULL; + peer_cfg_t *config; + identification_t *id; + linked_list_t *vips, *pools; + host_t *requested; + + id = this->ike_sa->get_other_eap_id(this->ike_sa); + config = this->ike_sa->get_peer_cfg(this->ike_sa); + vips = linked_list_create(); + pools = linked_list_create_from_enumerator( + config->create_pool_enumerator(config)); + + this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE); + + enumerator = this->vips->create_enumerator(this->vips); + while (enumerator->enumerate(enumerator, &requested)) + { + host_t *found = NULL; + + /* query all pools until we get an address */ + DBG1(DBG_IKE, "peer requested virtual IP %H", requested); + + found = hydra->attributes->acquire_address(hydra->attributes, + pools, id, requested); + if (found) + { + DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id); + this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found); + if (!cp) + { + cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); + } + cp->add_attribute(cp, build_vip(found)); + vips->insert_last(vips, found); + } + else + { + DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'", + requested, id); + } + } + enumerator->destroy(enumerator); + + if (this->vips->get_count(this->vips) && !vips->get_count(vips)) + { + DBG1(DBG_IKE, "no virtual IP found, sending %N", + notify_type_names, INTERNAL_ADDRESS_FAILURE); + message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE, + chunk_empty); + vips->destroy_offset(vips, offsetof(host_t, destroy)); + pools->destroy(pools); + return SUCCESS; + } + if (pools->get_count(pools) && !this->vips->get_count(this->vips)) + { + DBG1(DBG_IKE, "expected a virtual IP request, sending %N", + notify_type_names, FAILED_CP_REQUIRED); + message->add_notify(message, FALSE, FAILED_CP_REQUIRED, chunk_empty); + vips->destroy_offset(vips, offsetof(host_t, destroy)); + pools->destroy(pools); + return SUCCESS; + } + + /* query registered providers for additional attributes to include */ + enumerator = hydra->attributes->create_responder_enumerator( + hydra->attributes, pools, id, vips); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (!cp) + { + cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); + } + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, value)); + } + enumerator->destroy(enumerator); + vips->destroy_offset(vips, offsetof(host_t, destroy)); + pools->destroy(pools); + + if (cp) + { + message->add_payload(message, (payload_t*)cp); + } + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_config_t *this, message_t *message) +{ + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ + enumerator_t *enumerator; + host_t *host; + + process_payloads(this, message); + + this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE); + + enumerator = this->vips->create_enumerator(this->vips); + while (enumerator->enumerate(enumerator, &host)) + { + if (!host->is_anyaddr(host)) + { + this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host); + } + } + enumerator->destroy(enumerator); + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_config_t *this) +{ + return TASK_IKE_CONFIG; +} + +METHOD(task_t, migrate, void, + private_ike_config_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->vips = linked_list_create(); + this->requested->destroy_function(this->requested, free); + this->requested = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_ike_config_t *this) +{ + this->vips->destroy_offset(this->vips, offsetof(host_t, destroy)); + this->requested->destroy_function(this->requested, free); + free(this); +} + +/* + * Described in header. + */ +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_config_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .vips = linked_list_create(), + .requested = linked_list_create(), + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_config.h b/src/libcharon/sa/ikev2/tasks/ike_config.h new file mode 100644 index 000000000..e35457645 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_config.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_config ike_config + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_CONFIG_H_ +#define IKE_CONFIG_H_ + +typedef struct ike_config_t ike_config_t; + +#include +#include +#include + +/** + * Task of type TASK_IKE_CONFIG, sets up a virtual IP and other + * configurations for an IKE_SA. + */ +struct ike_config_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_config task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return ike_config task to handle by the task_manager + */ +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_CONFIG_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c new file mode 100644 index 000000000..f127b0c15 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_delete.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2006-2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_delete.h" + +#include +#include + + +typedef struct private_ike_delete_t private_ike_delete_t; + +/** + * Private members of a ike_delete_t task. + */ +struct private_ike_delete_t { + + /** + * Public methods and task_t interface. + */ + ike_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * are we deleting a rekeyed SA? + */ + bool rekeyed; + + /** + * are we responding to a delete, but have initated our own? + */ + bool simultaneous; +}; + +METHOD(task_t, build_i, status_t, + private_ike_delete_t *this, message_t *message) +{ + delete_payload_t *delete_payload; + + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + delete_payload = delete_payload_create(DELETE, PROTO_IKE); + message->add_payload(message, (payload_t*)delete_payload); + + if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) + { + this->rekeyed = TRUE; + } + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + + DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_delete_t *this, message_t *message) +{ + DBG0(DBG_IKE, "IKE_SA deleted"); + if (!this->rekeyed) + { /* invoke ike_down() hook if SA has not been rekeyed */ + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + /* completed, delete IKE_SA by returning DESTROY_ME */ + return DESTROY_ME; +} + +METHOD(task_t, process_r, status_t, + private_ike_delete_t *this, message_t *message) +{ + /* we don't even scan the payloads, as the message wouldn't have + * come so far without being correct */ + DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_ESTABLISHED: + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + this->ike_sa->reestablish(this->ike_sa); + return NEED_MORE; + case IKE_REKEYING: + this->rekeyed = TRUE; + break; + case IKE_DELETING: + this->simultaneous = TRUE; + break; + default: + break; + } + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_delete_t *this, message_t *message) +{ + DBG0(DBG_IKE, "IKE_SA deleted"); + + if (this->simultaneous) + { + /* wait for peer's response for our delete request */ + return SUCCESS; + } + if (!this->rekeyed) + { /* invoke ike_down() hook if SA has not been rekeyed */ + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + /* completed, delete IKE_SA by returning DESTROY_ME */ + return DESTROY_ME; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_delete_t *this) +{ + return TASK_IKE_DELETE; +} + +METHOD(task_t, migrate, void, + private_ike_delete_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->simultaneous = FALSE; +} + +METHOD(task_t, destroy, void, + private_ike_delete_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.h b/src/libcharon/sa/ikev2/tasks/ike_delete.h new file mode 100644 index 000000000..2d5d7cb3a --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_delete.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_delete ike_delete + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_DELETE_H_ +#define IKE_DELETE_H_ + +typedef struct ike_delete_t ike_delete_t; + +#include +#include +#include + +/** + * Task of type ike_delete, delete an IKE_SA. + */ +struct ike_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if we initiate the delete + * @return ike_delete task to handle by the task_manager + */ +ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_dpd.c b/src/libcharon/sa/ikev2/tasks/ike_dpd.c new file mode 100644 index 000000000..28ccc2efe --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_dpd.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_dpd.h" + +#include + + +typedef struct private_ike_dpd_t private_ike_dpd_t; + +/** + * Private members of a ike_dpd_t task. + */ +struct private_ike_dpd_t { + + /** + * Public methods and task_t interface. + */ + ike_dpd_t public; +}; + +METHOD(task_t, return_need_more, status_t, + private_ike_dpd_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, return_success, status_t, + private_ike_dpd_t *this, message_t *message) +{ + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_dpd_t *this) +{ + return TASK_IKE_DPD; +} + + +METHOD(task_t, migrate, void, + private_ike_dpd_t *this, ike_sa_t *ike_sa) +{ + +} + +METHOD(task_t, destroy, void, + private_ike_dpd_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_dpd_t *ike_dpd_create(bool initiator) +{ + private_ike_dpd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + ); + + if (initiator) + { + this->public.task.build = _return_need_more; + this->public.task.process = _return_success; + } + else + { + this->public.task.build = _return_success; + this->public.task.process = _return_need_more; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_dpd.h b/src/libcharon/sa/ikev2/tasks/ike_dpd.h new file mode 100644 index 000000000..026871610 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_dpd.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_dpd ike_dpd + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_DPD_H_ +#define IKE_DPD_H_ + +typedef struct ike_dpd_t ike_dpd_t; + +#include +#include +#include + +/** + * Task of type ike_dpd, detects dead peers. + * + * The DPD task actually does nothing, as a DPD has no associated payloads. + */ +struct ike_dpd_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_dpd task. + * + * @param initiator TRUE if task is the original initiator + * @return ike_dpd task to handle by the task_manager + */ +ike_dpd_t *ike_dpd_create(bool initiator); + +#endif /** IKE_DPD_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c new file mode 100644 index 000000000..f2a06735e --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_init.h" + +#include + +#include +#include +#include +#include +#include +#include + +/** maximum retries to do with cookies/other dh groups */ +#define MAX_RETRIES 5 + +typedef struct private_ike_init_t private_ike_init_t; + +/** + * Private members of a ike_init_t task. + */ +struct private_ike_init_t { + + /** + * Public methods and task_t interface. + */ + ike_init_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * IKE config to establish + */ + ike_cfg_t *config; + + /** + * diffie hellman group to use + */ + diffie_hellman_group_t dh_group; + + /** + * diffie hellman key exchange + */ + diffie_hellman_t *dh; + + /** + * Keymat derivation (from IKE_SA) + */ + keymat_v2_t *keymat; + + /** + * nonce chosen by us + */ + chunk_t my_nonce; + + /** + * nonce chosen by peer + */ + chunk_t other_nonce; + + /** + * Negotiated proposal used for IKE_SA + */ + proposal_t *proposal; + + /** + * Old IKE_SA which gets rekeyed + */ + ike_sa_t *old_sa; + + /** + * cookie received from responder + */ + chunk_t cookie; + + /** + * retries done so far after failure (cookie or bad dh group) + */ + u_int retry; +}; + +/** + * build the payloads for the message + */ +static void build_payloads(private_ike_init_t *this, message_t *message) +{ + sa_payload_t *sa_payload; + ke_payload_t *ke_payload; + nonce_payload_t *nonce_payload; + linked_list_t *proposal_list; + ike_sa_id_t *id; + proposal_t *proposal; + enumerator_t *enumerator; + + id = this->ike_sa->get_id(this->ike_sa); + + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + + if (this->initiator) + { + proposal_list = this->config->get_proposals(this->config); + if (this->old_sa) + { + /* include SPI of new IKE_SA when we are rekeying */ + enumerator = proposal_list->create_enumerator(proposal_list); + while (enumerator->enumerate(enumerator, (void**)&proposal)) + { + proposal->set_spi(proposal, id->get_initiator_spi(id)); + } + enumerator->destroy(enumerator); + } + + sa_payload = sa_payload_create_from_proposals_v2(proposal_list); + proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); + } + else + { + if (this->old_sa) + { + /* include SPI of new IKE_SA when we are rekeying */ + this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); + } + sa_payload = sa_payload_create_from_proposal_v2(this->proposal); + } + message->add_payload(message, (payload_t*)sa_payload); + + nonce_payload = nonce_payload_create(NONCE); + nonce_payload->set_nonce(nonce_payload, this->my_nonce); + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE, this->dh); + + if (this->old_sa) + { /* payload order differs if we are rekeying */ + message->add_payload(message, (payload_t*)nonce_payload); + message->add_payload(message, (payload_t*)ke_payload); + } + else + { + message->add_payload(message, (payload_t*)ke_payload); + message->add_payload(message, (payload_t*)nonce_payload); + } +} + +/** + * Read payloads from message + */ +static void process_payloads(private_ike_init_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case SECURITY_ASSOCIATION: + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + linked_list_t *proposal_list; + bool private; + + proposal_list = sa_payload->get_proposals(sa_payload); + private = this->ike_sa->supports_extension(this->ike_sa, + EXT_STRONGSWAN); + this->proposal = this->config->select_proposal(this->config, + proposal_list, private); + proposal_list->destroy_offset(proposal_list, + offsetof(proposal_t, destroy)); + break; + } + case KEY_EXCHANGE: + { + ke_payload_t *ke_payload = (ke_payload_t*)payload; + + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + if (!this->initiator) + { + this->dh = this->keymat->keymat.create_dh( + &this->keymat->keymat, this->dh_group); + } + if (this->dh) + { + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + } + break; + } + case NONCE: + { + nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; + + this->other_nonce = nonce_payload->get_nonce(nonce_payload); + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_ike_init_t *this, message_t *message) +{ + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + if (this->retry >= MAX_RETRIES) + { + DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES); + return FAILED; + } + + /* if the DH group is set via use_dh_group(), we already have a DH object */ + if (!this->dh) + { + this->dh_group = this->config->get_dh_group(this->config); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); + if (!this->dh) + { + DBG1(DBG_IKE, "configured DH group %N not supported", + diffie_hellman_group_names, this->dh_group); + return FAILED; + } + } + + /* generate nonce only when we are trying the first time */ + if (this->my_nonce.ptr == NULL) + { + nonce_gen_t *nonceg; + + nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); + if (!nonceg) + { + DBG1(DBG_IKE, "no nonce generator found to create nonce"); + return FAILED; + } + if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce)) + { + DBG1(DBG_IKE, "nonce allocation failed"); + nonceg->destroy(nonceg); + return FAILED; + } + nonceg->destroy(nonceg); + } + + if (this->cookie.ptr) + { + message->add_notify(message, FALSE, COOKIE, this->cookie); + } + + build_payloads(this, message); + +#ifdef ME + { + chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa); + if (connect_id.ptr) + { + message->add_notify(message, FALSE, ME_CONNECTID, connect_id); + } + } +#endif /* ME */ + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_init_t *this, message_t *message) +{ + nonce_gen_t *nonceg; + + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat); + if (!nonceg) + { + DBG1(DBG_IKE, "no nonce generator found to create nonce"); + return FAILED; + } + if (!nonceg->allocate_nonce(nonceg, NONCE_SIZE, &this->my_nonce)) + { + DBG1(DBG_IKE, "nonce allocation failed"); + nonceg->destroy(nonceg); + return FAILED; + } + nonceg->destroy(nonceg); + +#ifdef ME + { + notify_payload_t *notify = message->get_notify(message, ME_CONNECTID); + if (notify) + { + chunk_t connect_id = notify->get_notification_data(notify); + DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id); + charon->connect_manager->stop_checks(charon->connect_manager, + connect_id); + } + } +#endif /* ME */ + + process_payloads(this, message); + + return NEED_MORE; +} + +/** + * Derive the keymat for the IKE_SA + */ +static bool derive_keys(private_ike_init_t *this, + chunk_t nonce_i, chunk_t nonce_r) +{ + keymat_v2_t *old_keymat; + pseudo_random_function_t prf_alg = PRF_UNDEFINED; + chunk_t skd = chunk_empty; + ike_sa_id_t *id; + + id = this->ike_sa->get_id(this->ike_sa); + if (this->old_sa) + { + /* rekeying: Include old SKd, use old PRF, apply SPI */ + old_keymat = (keymat_v2_t*)this->old_sa->get_keymat(this->old_sa); + prf_alg = old_keymat->get_skd(old_keymat, &skd); + if (this->initiator) + { + id->set_responder_spi(id, this->proposal->get_spi(this->proposal)); + } + else + { + id->set_initiator_spi(id, this->proposal->get_spi(this->proposal)); + } + } + if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, + nonce_i, nonce_r, id, prf_alg, skd)) + { + return FALSE; + } + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty, + nonce_i, nonce_r, this->old_sa, NULL); + return TRUE; +} + +METHOD(task_t, build_r, status_t, + private_ike_init_t *this, message_t *message) +{ + /* check if we have everything we need */ + if (this->proposal == NULL || + this->other_nonce.len == 0 || this->my_nonce.len == 0) + { + DBG1(DBG_IKE, "received proposals inacceptable"); + message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); + return FAILED; + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group)) + { + u_int16_t group; + + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &group, NULL)) + { + DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + group = htons(group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + } + else + { + DBG1(DBG_IKE, "no acceptable proposal found"); + } + return FAILED; + } + + if (!derive_keys(this, this->other_nonce, this->my_nonce)) + { + DBG1(DBG_IKE, "key derivation failed"); + message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); + return FAILED; + } + build_payloads(this, message); + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_ike_init_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + + /* check for erronous notifies */ + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + notify_type_t type = notify->get_notify_type(notify); + + switch (type) + { + case INVALID_KE_PAYLOAD: + { + chunk_t data; + diffie_hellman_group_t bad_group; + + bad_group = this->dh_group; + data = notify->get_notification_data(notify); + this->dh_group = ntohs(*((u_int16_t*)data.ptr)); + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + bad_group, diffie_hellman_group_names, this->dh_group); + + if (this->old_sa == NULL) + { /* reset the IKE_SA if we are not rekeying */ + this->ike_sa->reset(this->ike_sa); + } + + enumerator->destroy(enumerator); + this->retry++; + return NEED_MORE; + } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + /* skip, handled in ike_natd_t */ + break; + case MULTIPLE_AUTH_SUPPORTED: + /* handled in ike_auth_t */ + break; + case COOKIE: + { + chunk_free(&this->cookie); + this->cookie = chunk_clone(notify->get_notification_data(notify)); + this->ike_sa->reset(this->ike_sa); + enumerator->destroy(enumerator); + DBG2(DBG_IKE, "received %N notify", notify_type_names, type); + this->retry++; + return NEED_MORE; + } + default: + { + if (type <= 16383) + { + DBG1(DBG_IKE, "received %N notify error", + notify_type_names, type); + enumerator->destroy(enumerator); + return FAILED; + } + DBG2(DBG_IKE, "received %N notify", + notify_type_names, type); + break; + } + } + } + } + enumerator->destroy(enumerator); + + process_payloads(this, message); + + /* check if we have everything */ + if (this->proposal == NULL || + this->other_nonce.len == 0 || this->my_nonce.len == 0) + { + DBG1(DBG_IKE, "peers proposal selection invalid"); + return FAILED; + } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group)) + { + DBG1(DBG_IKE, "peer DH group selection invalid"); + return FAILED; + } + + if (!derive_keys(this, this->my_nonce, this->other_nonce)) + { + DBG1(DBG_IKE, "key derivation failed"); + return FAILED; + } + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_init_t *this) +{ + return TASK_IKE_INIT; +} + +METHOD(task_t, migrate, void, + private_ike_init_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->proposal); + chunk_free(&this->other_nonce); + + this->ike_sa = ike_sa; + this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + this->proposal = NULL; + if (this->dh && this->dh->get_dh_group(this->dh) != this->dh_group) + { /* reset DH value only if group changed (INVALID_KE_PAYLOAD) */ + this->dh->destroy(this->dh); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); + } +} + +METHOD(task_t, destroy, void, + private_ike_init_t *this) +{ + DESTROY_IF(this->dh); + DESTROY_IF(this->proposal); + chunk_free(&this->my_nonce); + chunk_free(&this->other_nonce); + chunk_free(&this->cookie); + free(this); +} + +METHOD(ike_init_t, get_lower_nonce, chunk_t, + private_ike_init_t *this) +{ + if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, + min(this->my_nonce.len, this->other_nonce.len)) < 0) + { + return this->my_nonce; + } + else + { + return this->other_nonce; + } +} + +/* + * Described in header. + */ +ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) +{ + private_ike_init_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .get_lower_nonce = _get_lower_nonce, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh_group = MODP_NONE, + .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), + .old_sa = old_sa, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.h b/src/libcharon/sa/ikev2/tasks/ike_init.h new file mode 100644 index 000000000..ab169954d --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_init.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_init ike_init + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_INIT_H_ +#define IKE_INIT_H_ + +typedef struct ike_init_t ike_init_t; + +#include +#include +#include + +/** + * Task of type TASK_IKE_INIT, creates an IKE_SA without authentication. + * + * The authentication of is handle in the ike_auth task. + */ +struct ike_init_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Get the lower of the two nonces, used for rekey collisions. + * + * @return lower nonce + */ + chunk_t (*get_lower_nonce) (ike_init_t *this); +}; + +/** + * Create a new TASK_IKE_INIT task. + * + * @param ike_sa IKE_SA this task works for (new one when rekeying) + * @param initiator TRUE if task is the original initiator + * @param old_sa old IKE_SA when we are rekeying + * @return ike_init task to handle by the task_manager + */ +ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa); + +#endif /** IKE_INIT_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_me.c b/src/libcharon/sa/ikev2/tasks/ike_me.c new file mode 100644 index 000000000..135c06d19 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_me.c @@ -0,0 +1,845 @@ +/* + * Copyright (C) 2007-2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_me.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define ME_CONNECTID_LEN 4 +#define ME_CONNECTKEY_LEN 16 + +typedef struct private_ike_me_t private_ike_me_t; + +/** + * Private members of a ike_me_t task. + */ +struct private_ike_me_t { + + /** + * Public methods and task_t interface. + */ + ike_me_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Is this a mediation connection? + */ + bool mediation; + + /** + * Is this the response from another peer? + */ + bool response; + + /** + * Gathered endpoints + */ + linked_list_t *local_endpoints; + + /** + * Parsed endpoints + */ + linked_list_t *remote_endpoints; + + /** + * Did the peer request a callback? + */ + bool callback; + + /** + * Did the connect fail? + */ + bool failed; + + /** + * Was there anything wrong with the payloads? + */ + bool invalid_syntax; + + /** + * The requested peer + */ + identification_t *peer_id; + /** + * Received ID used for connectivity checks + */ + chunk_t connect_id; + + /** + * Received key used for connectivity checks + */ + chunk_t connect_key; + + /** + * Peer config of the mediated connection + */ + peer_cfg_t *mediated_cfg; + +}; + +/** + * Adds a list of endpoints as notifies to a given message + */ +static void add_endpoints_to_message(message_t *message, linked_list_t *endpoints) +{ + enumerator_t *enumerator; + endpoint_notify_t *endpoint; + + enumerator = endpoints->create_enumerator(endpoints); + while (enumerator->enumerate(enumerator, (void**)&endpoint)) + { + message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); + } + enumerator->destroy(enumerator); +} + +/** + * Gathers endpoints and adds them to the current message + */ +static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) +{ + enumerator_t *enumerator; + host_t *addr, *host; + u_int16_t port; + + /* get the port that is used to communicate with the ms */ + host = this->ike_sa->get_my_host(this->ike_sa); + port = host->get_port(host); + + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, ADDR_TYPE_REGULAR); + while (enumerator->enumerate(enumerator, (void**)&addr)) + { + host = addr->clone(addr); + host->set_port(host, port); + + this->local_endpoints->insert_last(this->local_endpoints, + endpoint_notify_create_from_host(HOST, host, NULL)); + + host->destroy(host); + } + enumerator->destroy(enumerator); + + host = this->ike_sa->get_server_reflexive_host(this->ike_sa); + if (host) + { + this->local_endpoints->insert_last(this->local_endpoints, + endpoint_notify_create_from_host(SERVER_REFLEXIVE, host, + this->ike_sa->get_my_host(this->ike_sa))); + } + + add_endpoints_to_message(message, this->local_endpoints); +} + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_me_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) != NOTIFY) + { + continue; + } + + notify_payload_t *notify = (notify_payload_t*)payload; + + switch (notify->get_notify_type(notify)) + { + case ME_CONNECT_FAILED: + { + DBG2(DBG_IKE, "received ME_CONNECT_FAILED notify"); + this->failed = TRUE; + break; + } + case ME_MEDIATION: + { + DBG2(DBG_IKE, "received ME_MEDIATION notify"); + this->mediation = TRUE; + break; + } + case ME_ENDPOINT: + { + endpoint_notify_t *endpoint; + endpoint = endpoint_notify_create_from_payload(notify); + if (!endpoint) + { + DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify"); + break; + } + DBG1(DBG_IKE, "received %N ME_ENDPOINT %#H", + me_endpoint_type_names, endpoint->get_type(endpoint), + endpoint->get_host(endpoint)); + + this->remote_endpoints->insert_last(this->remote_endpoints, + endpoint); + break; + } + case ME_CALLBACK: + { + DBG2(DBG_IKE, "received ME_CALLBACK notify"); + this->callback = TRUE; + break; + } + case ME_CONNECTID: + { + chunk_free(&this->connect_id); + this->connect_id = chunk_clone(notify->get_notification_data(notify)); + DBG2(DBG_IKE, "received ME_CONNECTID %#B", &this->connect_id); + break; + } + case ME_CONNECTKEY: + { + chunk_free(&this->connect_key); + this->connect_key = chunk_clone(notify->get_notification_data(notify)); + DBG4(DBG_IKE, "received ME_CONNECTKEY %#B", &this->connect_key); + break; + } + case ME_RESPONSE: + { + DBG2(DBG_IKE, "received ME_RESPONSE notify"); + this->response = TRUE; + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case IKE_SA_INIT: + { + peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->is_mediation(peer_cfg)) + { + DBG2(DBG_IKE, "adding ME_MEDIATION"); + message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty); + } + else + { + return SUCCESS; + } + break; + } + case IKE_AUTH: + { + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) + { + endpoint_notify_t *endpoint; + endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE, + NULL, NULL); + message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); + endpoint->destroy(endpoint); + } + break; + } + case ME_CONNECT: + { + rng_t *rng; + id_payload_t *id_payload; + id_payload = id_payload_create_from_identification(ID_PEER, + this->peer_id); + message->add_payload(message, (payload_t*)id_payload); + + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (!rng) + { + DBG1(DBG_IKE, "unable to generate connect ID for ME_CONNECT"); + return FAILED; + } + if (!this->response) + { + /* only the initiator creates a connect ID. the responder + * returns the connect ID that it received from the initiator */ + if (!rng->allocate_bytes(rng, ME_CONNECTID_LEN, + &this->connect_id)) + { + DBG1(DBG_IKE, "unable to generate ID for ME_CONNECT"); + rng->destroy(rng); + return FAILED; + } + } + if (!rng->allocate_bytes(rng, ME_CONNECTKEY_LEN, + &this->connect_key)) + { + DBG1(DBG_IKE, "unable to generate connect key for ME_CONNECT"); + rng->destroy(rng); + return FAILED; + } + rng->destroy(rng); + + message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id); + message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key); + + if (this->response) + { + message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty); + } + else + { + /* FIXME: should we make this configurable? */ + message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty); + } + + gather_and_add_endpoints(this, message); + + break; + } + default: + break; + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case ME_CONNECT: + { + id_payload_t *id_payload; + id_payload = (id_payload_t*)message->get_payload(message, ID_PEER); + if (!id_payload) + { + DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload" + ", aborting"); + break; + } + this->peer_id = id_payload->get_identification(id_payload); + + process_payloads(this, message); + + if (this->callback) + { + DBG1(DBG_IKE, "received ME_CALLBACK for '%Y'", this->peer_id); + break; + } + + if (!this->connect_id.ptr) + { + DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify" + ", aborting"); + this->invalid_syntax = TRUE; + break; + } + + if (!this->connect_key.ptr) + { + DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY " + "notify, aborting"); + this->invalid_syntax = TRUE; + break; + } + + if (!this->remote_endpoints->get_count(this->remote_endpoints)) + { + DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT " + "payloads, aborting"); + this->invalid_syntax = TRUE; + break; + } + + DBG1(DBG_IKE, "received ME_CONNECT"); + break; + } + default: + break; + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case ME_CONNECT: + { + if (this->invalid_syntax) + { + message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty); + break; + } + + if (this->callback) + { + /* we got a callback from the mediation server, initiate the + * queued mediated connecction */ + charon->connect_manager->check_and_initiate( + charon->connect_manager, + this->ike_sa->get_id(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), this->peer_id); + return SUCCESS; + } + + if (this->response) + { + /* FIXME: handle result of set_responder_data + * as initiator, upon receiving a response from another peer, + * update the checklist and start sending checks */ + charon->connect_manager->set_responder_data( + charon->connect_manager, + this->connect_id, this->connect_key, + this->remote_endpoints); + } + else + { + /* FIXME: handle result of set_initiator_data + * as responder, create a checklist with the initiator's data */ + charon->connect_manager->set_initiator_data( + charon->connect_manager, + this->peer_id, this->ike_sa->get_my_id(this->ike_sa), + this->connect_id, this->connect_key, + this->remote_endpoints, FALSE); + if (this->ike_sa->respond(this->ike_sa, this->peer_id, + this->connect_id) != SUCCESS) + { + return FAILED; + } + } + break; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case IKE_SA_INIT: + { + process_payloads(this, message); + if (!this->mediation) + { + DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting"); + return FAILED; + } + /* if we are on a mediation connection we switch to port 4500 even + * if no NAT is detected. */ + this->ike_sa->float_ports(this->ike_sa); + return NEED_MORE; + } + case IKE_AUTH: + { + process_payloads(this, message); + /* FIXME: we should update the server reflexive endpoint somehow, + * if mobike notices a change */ + endpoint_notify_t *reflexive; + if (this->remote_endpoints->get_first(this->remote_endpoints, + (void**)&reflexive) == SUCCESS && + reflexive->get_type(reflexive) == SERVER_REFLEXIVE) + { /* FIXME: should we accept this endpoint even if we did not send + * a request? */ + host_t *endpoint = reflexive->get_host(reflexive); + endpoint = endpoint->clone(endpoint); + this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint); + } + break; + } + case ME_CONNECT: + { + process_payloads(this, message); + + if (this->failed) + { + DBG1(DBG_IKE, "peer '%Y' is not online", this->peer_id); + /* FIXME: notify the mediated connection (job?) */ + } + else + { + if (this->response) + { + /* FIXME: handle result of set_responder_data. */ + /* as responder, we update the checklist and start sending + * checks */ + charon->connect_manager->set_responder_data( + charon->connect_manager, this->connect_id, + this->connect_key, this->local_endpoints); + } + else + { + /* FIXME: handle result of set_initiator_data */ + /* as initiator, we create a checklist and set the + * initiator's data */ + charon->connect_manager->set_initiator_data( + charon->connect_manager, + this->ike_sa->get_my_id(this->ike_sa), + this->peer_id, this->connect_id, this->connect_key, + this->local_endpoints, TRUE); + /* FIXME: also start a timer for the whole transaction + * (maybe within the connect_manager?) */ + } + } + break; + } + default: + break; + } + return SUCCESS; +} + +/** + * For mediation server + */ +METHOD(task_t, build_i_ms, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case ME_CONNECT: + { + id_payload_t *id_payload; + id_payload = id_payload_create_from_identification(ID_PEER, + this->peer_id); + message->add_payload(message, (payload_t*)id_payload); + + if (this->callback) + { + message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty); + } + else + { + if (this->response) + { + message->add_notify(message, FALSE, ME_RESPONSE, + chunk_empty); + } + message->add_notify(message, FALSE, ME_CONNECTID, + this->connect_id); + message->add_notify(message, FALSE, ME_CONNECTKEY, + this->connect_key); + add_endpoints_to_message(message, this->remote_endpoints); + } + break; + } + default: + break; + } + return NEED_MORE; +} + +/** + * For mediation server + */ +METHOD(task_t, process_r_ms, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case IKE_SA_INIT: + { + /* FIXME: we should check for SA* and TS* payloads. if there are + * any, send NO_ADDITIONAL_SAS back and delete this SA */ + process_payloads(this, message); + return this->mediation ? NEED_MORE : SUCCESS; + } + case IKE_AUTH: + { + /* FIXME: we should check whether the current peer_config is + * configured as mediation connection */ + process_payloads(this, message); + break; + } + case CREATE_CHILD_SA: + { + /* FIXME: if this is not to rekey the IKE SA we have to return a + * NO_ADDITIONAL_SAS and then delete the SA */ + break; + } + case ME_CONNECT: + { + id_payload_t *id_payload; + id_payload = (id_payload_t*)message->get_payload(message, ID_PEER); + if (!id_payload) + { + DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload" + ", aborting"); + this->invalid_syntax = TRUE; + break; + } + this->peer_id = id_payload->get_identification(id_payload); + + process_payloads(this, message); + + if (!this->connect_id.ptr) + { + DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify" + ", aborting"); + this->invalid_syntax = TRUE; + break; + } + + if (!this->connect_key.ptr) + { + DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify" + ", aborting"); + this->invalid_syntax = TRUE; + break; + } + + if (!this->remote_endpoints->get_count(this->remote_endpoints)) + { + DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT " + "payloads, aborting"); + this->invalid_syntax = TRUE; + break; + } + break; + } + default: + break; + } + return NEED_MORE; +} + +/** + * For mediation server + */ +METHOD(task_t, build_r_ms, status_t, + private_ike_me_t *this, message_t *message) +{ + switch(message->get_exchange_type(message)) + { + case IKE_SA_INIT: + { + message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty); + return NEED_MORE; + } + case IKE_AUTH: + { + endpoint_notify_t *endpoint; + if (this->remote_endpoints->get_first(this->remote_endpoints, + (void**)&endpoint) == SUCCESS && + endpoint->get_type(endpoint) == SERVER_REFLEXIVE) + { + host_t *host = this->ike_sa->get_other_host(this->ike_sa); + DBG2(DBG_IKE, "received request for a server reflexive " + "endpoint sending: %#H", host); + endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE, + host, NULL); + message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); + endpoint->destroy(endpoint); + } + this->ike_sa->act_as_mediation_server(this->ike_sa); + break; + } + case ME_CONNECT: + { + if (this->invalid_syntax) + { + message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty); + break; + } + + ike_sa_id_t *peer_sa; + if (this->callback) + { + peer_sa = charon->mediation_manager->check_and_register( + charon->mediation_manager, this->peer_id, + this->ike_sa->get_other_id(this->ike_sa)); + } + else + { + peer_sa = charon->mediation_manager->check( + charon->mediation_manager, this->peer_id); + } + + if (!peer_sa) + { + /* the peer is not online */ + message->add_notify(message, TRUE, ME_CONNECT_FAILED, + chunk_empty); + break; + } + + job_t *job = (job_t*)mediation_job_create(this->peer_id, + this->ike_sa->get_other_id(this->ike_sa), this->connect_id, + this->connect_key, this->remote_endpoints, this->response); + lib->processor->queue_job(lib->processor, job); + break; + } + default: + break; + } + return SUCCESS; +} + +/** + * For mediation server + */ +METHOD(task_t, process_i_ms, status_t, + private_ike_me_t *this, message_t *message) +{ + /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED + * here if the responding peer is not able to proceed. in this case we shall + * notify the initiating peer with a ME_CONNECT request containing only a + * ME_CONNECT_FAILED */ + return SUCCESS; +} + +METHOD(ike_me_t, me_connect, void, + private_ike_me_t *this, identification_t *peer_id) +{ + this->peer_id = peer_id->clone(peer_id); +} + +METHOD(ike_me_t, me_respond, void, + private_ike_me_t *this, identification_t *peer_id, chunk_t connect_id) +{ + this->peer_id = peer_id->clone(peer_id); + this->connect_id = chunk_clone(connect_id); + this->response = TRUE; +} + +METHOD(ike_me_t, me_callback, void, + private_ike_me_t *this, identification_t *peer_id) +{ + this->peer_id = peer_id->clone(peer_id); + this->callback = TRUE; +} + +METHOD(ike_me_t, relay, void, + private_ike_me_t *this, identification_t *requester, chunk_t connect_id, + chunk_t connect_key, linked_list_t *endpoints, bool response) +{ + this->peer_id = requester->clone(requester); + this->connect_id = chunk_clone(connect_id); + this->connect_key = chunk_clone(connect_key); + + this->remote_endpoints->destroy_offset(this->remote_endpoints, + offsetof(endpoint_notify_t, destroy)); + this->remote_endpoints = endpoints->clone_offset(endpoints, + offsetof(endpoint_notify_t, clone)); + + this->response = response; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_me_t *this) +{ + return TASK_IKE_ME; +} + +METHOD(task_t, migrate, void, + private_ike_me_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_me_t *this) +{ + DESTROY_IF(this->peer_id); + + chunk_free(&this->connect_id); + chunk_free(&this->connect_key); + + this->local_endpoints->destroy_offset(this->local_endpoints, + offsetof(endpoint_notify_t, destroy)); + this->remote_endpoints->destroy_offset(this->remote_endpoints, + offsetof(endpoint_notify_t, destroy)); + + DESTROY_IF(this->mediated_cfg); + free(this); +} + +/* + * Described in header. + */ +ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_me_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .connect = _me_connect, + .respond = _me_respond, + .callback = _me_callback, + .relay = _relay, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .local_endpoints = linked_list_create(), + .remote_endpoints = linked_list_create(), + ); + + if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR)) + { + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + } + else + { + /* mediation server */ + if (initiator) + { + this->public.task.build = _build_i_ms; + this->public.task.process = _process_i_ms; + } + else + { + this->public.task.build = _build_r_ms; + this->public.task.process = _process_r_ms; + } + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_me.h b/src/libcharon/sa/ikev2/tasks/ike_me.h new file mode 100644 index 000000000..44a4ce69c --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_me.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_me ike_me + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_ME_H_ +#define IKE_ME_H_ + +typedef struct ike_me_t ike_me_t; + +#include +#include +#include + +/** + * Task of type TASK_IKE_ME, detects and handles IKE-ME extensions. + * + * This tasks handles the ME_MEDIATION Notify exchange to setup a mediation + * connection, allows to initiate mediated connections using ME_CONNECT + * exchanges and to request reflexive addresses from the mediation server using + * ME_ENDPOINT notifies. + * + * @note This task has to be activated before the IKE_AUTH task, because that + * task generates the IKE_SA_INIT message so that no more payloads can be added + * to it afterwards. + */ +struct ike_me_t { + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Initiates a connection with another peer (i.e. sends a ME_CONNECT + * to the mediation server) + * + * @param peer_id ID of the other peer (gets cloned) + */ + void (*connect)(ike_me_t *this, identification_t *peer_id); + + /** + * Responds to a ME_CONNECT from another peer (i.e. sends a ME_CONNECT + * to the mediation server) + * + * Data gets cloned. + * + * @param peer_id ID of the other peer + * @param connect_id the connect ID as provided by the initiator + */ + void (*respond)(ike_me_t *this, identification_t *peer_id, + chunk_t connect_id); + + /** + * Sends a ME_CALLBACK to a peer that previously requested some other peer. + * + * @param peer_id ID of the other peer (gets cloned) + */ + void (*callback)(ike_me_t *this, identification_t *peer_id); + + /** + * Relays data to another peer (i.e. sends a ME_CONNECT to the peer) + * + * Data gets cloned. + * + * @param requester ID of the requesting peer + * @param connect_id content of the ME_CONNECTID notify + * @param connect_key content of the ME_CONNECTKEY notify + * @param endpoints endpoints + * @param response TRUE if this is a response + */ + void (*relay)(ike_me_t *this, identification_t *requester, + chunk_t connect_id, chunk_t connect_key, + linked_list_t *endpoints, bool response); +}; + +/** + * Create a new ike_me task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is initiated by us + * @return ike_me task to be handled by the task_manager + */ +ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_ME_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c new file mode 100644 index 000000000..ae3526f42 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -0,0 +1,670 @@ +/* + * Copyright (C) 2010-2012 Tobias Brunner + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_mobike.h" + +#include + +#include +#include +#include +#include + +#define COOKIE2_SIZE 16 +#define MAX_ADDITIONAL_ADDRS 8 + +typedef struct private_ike_mobike_t private_ike_mobike_t; + +/** + * Private members of a ike_mobike_t task. + */ +struct private_ike_mobike_t { + + /** + * Public methods and task_t interface. + */ + ike_mobike_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * cookie2 value to verify new addresses + */ + chunk_t cookie2; + + /** + * NAT discovery reusing the TASK_IKE_NATD task + */ + ike_natd_t *natd; + + /** + * use task to update addresses + */ + bool update; + + /** + * do routability check + */ + bool check; + + /** + * include address list update + */ + bool address; + + /** + * additional addresses got updated + */ + bool addresses_updated; +}; + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_mobike_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool first = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + int family = AF_INET; + notify_payload_t *notify; + chunk_t data; + host_t *host; + + if (payload->get_type(payload) != NOTIFY) + { + continue; + } + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case MOBIKE_SUPPORTED: + { + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!this->initiator && + peer_cfg && !peer_cfg->use_mobike(peer_cfg)) + { + DBG1(DBG_IKE, "peer supports MOBIKE, but disabled in config"); + } + else + { + DBG1(DBG_IKE, "peer supports MOBIKE"); + this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); + } + break; + } + case COOKIE2: + { + chunk_free(&this->cookie2); + this->cookie2 = chunk_clone(notify->get_notification_data(notify)); + break; + } + case ADDITIONAL_IP6_ADDRESS: + { + family = AF_INET6; + /* fall through */ + } + case ADDITIONAL_IP4_ADDRESS: + { + if (first) + { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ + this->ike_sa->clear_peer_addresses(this->ike_sa); + first = FALSE; + /* add the peer's current address to the list */ + host = message->get_source(message); + this->ike_sa->add_peer_address(this->ike_sa, + host->clone(host)); + } + data = notify->get_notification_data(notify); + host = host_create_from_chunk(family, data, 0); + DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); + this->ike_sa->add_peer_address(this->ike_sa, host); + this->addresses_updated = TRUE; + break; + } + case UPDATE_SA_ADDRESSES: + { + this->update = TRUE; + break; + } + case NO_ADDITIONAL_ADDRESSES: + { + this->ike_sa->clear_peer_addresses(this->ike_sa); + /* add the peer's current address to the list */ + host = message->get_source(message); + this->ike_sa->add_peer_address(this->ike_sa, host->clone(host)); + this->addresses_updated = TRUE; + break; + } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + { + /* NAT check in this MOBIKE exchange, create subtask for it */ + if (this->natd == NULL) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Add ADDITIONAL_*_ADDRESS notifys depending on our address list + */ +static void build_address_list(private_ike_mobike_t *this, message_t *message) +{ + enumerator_t *enumerator; + host_t *host, *me; + notify_type_t type; + int added = 0; + + me = this->ike_sa->get_my_host(this->ike_sa); + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, ADDR_TYPE_REGULAR); + while (enumerator->enumerate(enumerator, (void**)&host)) + { + if (me->ip_equals(me, host)) + { /* "ADDITIONAL" means do not include IKE_SAs host */ + continue; + } + switch (host->get_family(host)) + { + case AF_INET: + type = ADDITIONAL_IP4_ADDRESS; + break; + case AF_INET6: + type = ADDITIONAL_IP6_ADDRESS; + break; + default: + continue; + } + message->add_notify(message, FALSE, type, host->get_address(host)); + if (++added >= MAX_ADDITIONAL_ADDRS) + { /* limit number of notifys, some implementations do not like too + * many of them (f.e. strongSwan ;-) */ + break; + } + } + if (!added) + { + message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty); + } + enumerator->destroy(enumerator); +} + +/** + * build a cookie and add it to the message + */ +static bool build_cookie(private_ike_mobike_t *this, message_t *message) +{ + rng_t *rng; + + chunk_free(&this->cookie2); + rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); + if (!rng || !rng->allocate_bytes(rng, COOKIE2_SIZE, &this->cookie2)) + { + DESTROY_IF(rng); + return FALSE; + } + message->add_notify(message, FALSE, COOKIE2, this->cookie2); + rng->destroy(rng); + return TRUE; +} + +/** + * update addresses of associated CHILD_SAs + */ +static void update_children(private_ike_mobike_t *this) +{ + enumerator_t *enumerator; + child_sa_t *child_sa; + linked_list_t *vips; + host_t *host; + + vips = linked_list_create(); + + enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE); + while (enumerator->enumerate(enumerator, &host)) + { + vips->insert_last(vips, host); + } + enumerator->destroy(enumerator); + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) + { + if (child_sa->update(child_sa, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), vips, + this->ike_sa->has_condition(this->ike_sa, + COND_NAT_ANY)) == NOT_SUPPORTED) + { + this->ike_sa->rekey_child_sa(this->ike_sa, + child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE)); + } + } + enumerator->destroy(enumerator); + + vips->destroy(vips); +} + +/** + * Apply the port of the old host, if its ip equals the new, use port otherwise. + */ +static void apply_port(host_t *host, host_t *old, u_int16_t port, bool local) +{ + if (host->ip_equals(host, old)) + { + port = old->get_port(old); + } + else if (local && port == charon->socket->get_port(charon->socket, FALSE)) + { + port = charon->socket->get_port(charon->socket, TRUE); + } + else if (!local && port == IKEV2_UDP_PORT) + { + port = IKEV2_NATT_PORT; + } + host->set_port(host, port); +} + +METHOD(ike_mobike_t, transmit, void, + private_ike_mobike_t *this, packet_t *packet) +{ + host_t *me, *other, *me_old, *other_old; + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + packet_t *copy; + + if (!this->check) + { + return; + } + + me_old = this->ike_sa->get_my_host(this->ike_sa); + other_old = this->ike_sa->get_other_host(this->ike_sa); + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + + enumerator = this->ike_sa->create_peer_address_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&other)) + { + me = hydra->kernel_interface->get_source_addr( + hydra->kernel_interface, other, NULL); + if (me) + { + if (me->get_family(me) != other->get_family(other)) + { + me->destroy(me); + continue; + } + /* reuse port for an active address, 4500 otherwise */ + apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg), TRUE); + other = other->clone(other); + apply_port(other, other_old, ike_cfg->get_other_port(ike_cfg), FALSE); + DBG1(DBG_IKE, "checking path %#H - %#H", me, other); + copy = packet->clone(packet); + copy->set_source(copy, me); + copy->set_destination(copy, other); + charon->sender->send(charon->sender, copy); + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { /* only in first IKE_AUTH */ + message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + host_t *old, *new; + + /* we check if the existing address is still valid */ + old = message->get_source(message); + new = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + message->get_destination(message), old); + if (new) + { + if (!new->ip_equals(new, old)) + { + new->set_port(new, old->get_port(old)); + message->set_source(message, new); + } + else + { + new->destroy(new); + } + } + if (this->update) + { + message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, + chunk_empty); + if (!build_cookie(this, message)) + { + return FAILED; + } + update_children(this); + } + if (this->address && !this->check) + { + build_address_list(this, message); + } + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { /* only first IKE_AUTH */ + process_payloads(this, message); + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + process_payloads(this, message); + if (this->update) + { + host_t *me, *other; + + me = message->get_destination(message); + other = message->get_source(message); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + } + if (this->addresses_updated && this->ike_sa->has_condition(this->ike_sa, + COND_ORIGINAL_INITIATOR)) + { + host_t *other = message->get_source(message); + host_t *other_old = this->ike_sa->get_other_host(this->ike_sa); + if (!other->equals(other, other_old)) + { + DBG1(DBG_IKE, "remote address changed from %H to %H", other_old, + other); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + this->update = TRUE; + } + } + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) + { + message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); + build_address_list(this, message); + } + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + if (this->natd) + { + this->natd->task.build(&this->natd->task, message); + } + if (this->cookie2.ptr) + { + message->add_notify(message, FALSE, COOKIE2, this->cookie2); + chunk_free(&this->cookie2); + } + if (this->update) + { + update_children(this); + } + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_mobike_t *this, message_t *message) +{ + if (message->get_exchange_type(message) == IKE_AUTH && + this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + process_payloads(this, message); + return SUCCESS; + } + else if (message->get_exchange_type(message) == INFORMATIONAL) + { + u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1; + this->ike_sa->set_pending_updates(this->ike_sa, updates); + if (updates > 0) + { + /* newer update queued, ignore this one */ + return SUCCESS; + } + if (this->cookie2.ptr) + { /* check cookie if we included one */ + chunk_t cookie2; + + cookie2 = this->cookie2; + this->cookie2 = chunk_empty; + process_payloads(this, message); + if (!chunk_equals(cookie2, this->cookie2)) + { + chunk_free(&cookie2); + DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA"); + return FAILED; + } + chunk_free(&cookie2); + } + else + { + process_payloads(this, message); + } + if (this->natd) + { + this->natd->task.process(&this->natd->task, message); + if (this->natd->has_mapping_changed(this->natd)) + { + /* force an update if mappings have changed */ + this->update = this->check = TRUE; + DBG1(DBG_IKE, "detected changes in NAT mappings, " + "initiating MOBIKE update"); + } + } + if (this->update) + { + /* update again, as NAT state may have changed */ + update_children(this); + } + if (this->check) + { + host_t *me_new, *me_old, *other_new, *other_old; + + me_new = message->get_destination(message); + other_new = message->get_source(message); + me_old = this->ike_sa->get_my_host(this->ike_sa); + other_old = this->ike_sa->get_other_host(this->ike_sa); + + if (!me_new->equals(me_new, me_old)) + { + this->update = TRUE; + this->ike_sa->set_my_host(this->ike_sa, me_new->clone(me_new)); + } + if (!other_new->equals(other_new, other_old)) + { + this->update = TRUE; + this->ike_sa->set_other_host(this->ike_sa, other_new->clone(other_new)); + } + if (this->update) + { + /* use the same task to ... */ + if (!this->ike_sa->has_condition(this->ike_sa, + COND_ORIGINAL_INITIATOR)) + { /*... send an updated list of addresses as responder */ + update_children(this); + this->update = FALSE; + } + else + { /* ... send the update as original initiator */ + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + this->check = FALSE; + this->ike_sa->set_pending_updates(this->ike_sa, 1); + return NEED_MORE; + } + } + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(ike_mobike_t, addresses, void, + private_ike_mobike_t *this) +{ + this->address = TRUE; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +METHOD(ike_mobike_t, roam, void, + private_ike_mobike_t *this, bool address) +{ + this->check = TRUE; + this->address = address; + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +METHOD(ike_mobike_t, dpd, void, + private_ike_mobike_t *this) +{ + if (!this->natd) + { + this->natd = ike_natd_create(this->ike_sa, this->initiator); + } + this->ike_sa->set_pending_updates(this->ike_sa, + this->ike_sa->get_pending_updates(this->ike_sa) + 1); +} + +METHOD(ike_mobike_t, is_probing, bool, + private_ike_mobike_t *this) +{ + return this->check; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_mobike_t *this) +{ + return TASK_IKE_MOBIKE; +} + +METHOD(task_t, migrate, void, + private_ike_mobike_t *this, ike_sa_t *ike_sa) +{ + chunk_free(&this->cookie2); + this->ike_sa = ike_sa; + if (this->natd) + { + this->natd->task.migrate(&this->natd->task, ike_sa); + } +} + +METHOD(task_t, destroy, void, + private_ike_mobike_t *this) +{ + chunk_free(&this->cookie2); + if (this->natd) + { + this->natd->task.destroy(&this->natd->task); + } + free(this); +} + +/* + * Described in header. + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_mobike_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .addresses = _addresses, + .roam = _roam, + .dpd = _dpd, + .transmit = _transmit, + .is_probing = _is_probing, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.h b/src/libcharon/sa/ikev2/tasks/ike_mobike.h new file mode 100644 index 000000000..3b447af51 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_mobike ike_mobike + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_MOBIKE_H_ +#define IKE_MOBIKE_H_ + +typedef struct ike_mobike_t ike_mobike_t; + +#include +#include +#include +#include + +/** + * Task of type ike_mobike, detects and handles MOBIKE extension. + * + * The MOBIKE extension is defined in RFC4555. It allows to update IKE + * and IPsec tunnel addresses. + * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE + * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional + * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update + * endpoints. + */ +struct ike_mobike_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Use the task to update the list of additional addresses. + */ + void (*addresses)(ike_mobike_t *this); + + /** + * Use the task to roam to other addresses. + * + * @param address TRUE to include address list update + */ + void (*roam)(ike_mobike_t *this, bool address); + + /** + * Use the task for a DPD check which detects changes in NAT mappings. + */ + void (*dpd)(ike_mobike_t *this); + + /** + * Transmision hook, called by task manager. + * + * The task manager calls this hook whenever it transmits a packet. It + * allows the mobike task to send the packet on multiple paths to do path + * probing. + * + * @param packet the packet to transmit + */ + void (*transmit)(ike_mobike_t *this, packet_t *packet); + + /** + * Check if this task is probing for routability. + * + * @return TRUE if task is probing + */ + bool (*is_probing)(ike_mobike_t *this); +}; + +/** + * Create a new ike_mobike task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if taks is initiated by us + * @return ike_mobike task to handle by the task_manager + */ +ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_MOBIKE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c new file mode 100644 index 000000000..0a93db9ed --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_natd.c @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_natd.h" + +#include + +#include +#include +#include +#include +#include + + +typedef struct private_ike_natd_t private_ike_natd_t; + +/** + * Private members of a ike_natd_t task. + */ +struct private_ike_natd_t { + + /** + * Public methods and task_t interface. + */ + ike_natd_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Hasher used to build NAT detection hashes + */ + hasher_t *hasher; + + /** + * Did we process any NAT detection notifys for a source address? + */ + bool src_seen; + + /** + * Did we process any NAT detection notifys for a destination address? + */ + bool dst_seen; + + /** + * Have we found a matching source address NAT hash? + */ + bool src_matched; + + /** + * Have we found a matching destination address NAT hash? + */ + bool dst_matched; + + /** + * whether NAT mappings for our NATed address has changed + */ + bool mapping_changed; +}; + + +/** + * Build NAT detection hash for a host + */ +static chunk_t generate_natd_hash(private_ike_natd_t *this, + ike_sa_id_t *ike_sa_id, host_t *host) +{ + chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk; + chunk_t natd_hash; + u_int64_t spi_i, spi_r; + u_int16_t port; + + /* prepare all required chunks */ + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi_i_chunk.ptr = (void*)&spi_i; + spi_i_chunk.len = sizeof(spi_i); + spi_r_chunk.ptr = (void*)&spi_r; + spi_r_chunk.len = sizeof(spi_r); + port = htons(host->get_port(host)); + port_chunk.ptr = (void*)&port; + port_chunk.len = sizeof(port); + addr_chunk = host->get_address(host); + + /* natd_hash = SHA1( spi_i | spi_r | address | port ) */ + natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk); + if (!this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash)) + { + natd_hash = chunk_empty; + } + DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk); + DBG3(DBG_IKE, "natd_hash %B", &natd_hash); + + chunk_free(&natd_chunk); + return natd_hash; +} + +/** + * build a faked NATD payload to enforce UDP encap + */ +static chunk_t generate_natd_hash_faked(private_ike_natd_t *this) +{ + rng_t *rng; + chunk_t chunk; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng || !rng->allocate_bytes(rng, HASH_SIZE_SHA1, &chunk)) + { + DBG1(DBG_IKE, "unable to get random bytes for NATD fake"); + DESTROY_IF(rng); + return chunk_empty; + } + rng->destroy(rng); + return chunk; +} + +/** + * Build a NAT detection notify payload. + */ +static notify_payload_t *build_natd_payload(private_ike_natd_t *this, + notify_type_t type, host_t *host) +{ + chunk_t hash; + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + ike_cfg_t *config; + + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP) + { + hash = generate_natd_hash_faked(this); + } + else + { + hash = generate_natd_hash(this, ike_sa_id, host); + } + if (!hash.len) + { + return NULL; + } + notify = notify_payload_create(NOTIFY); + notify->set_notify_type(notify, type); + notify->set_notification_data(notify, hash); + chunk_free(&hash); + + return notify; +} + +/** + * read notifys from message and evaluate them + */ +static void process_payloads(private_ike_natd_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + chunk_t hash, src_hash, dst_hash; + ike_sa_id_t *ike_sa_id; + host_t *me, *other; + ike_cfg_t *config; + + /* Precompute NAT-D hashes for incoming NAT notify comparison */ + ike_sa_id = message->get_ike_sa_id(message); + me = message->get_destination(message); + other = message->get_source(message); + dst_hash = generate_natd_hash(this, ike_sa_id, me); + src_hash = generate_natd_hash(this, ike_sa_id, other); + + DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); + DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) != NOTIFY) + { + continue; + } + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + case NAT_DETECTION_DESTINATION_IP: + { + this->dst_seen = TRUE; + hash = notify->get_notification_data(notify); + if (!this->dst_matched) + { + DBG3(DBG_IKE, "received dst_hash %B", &hash); + if (chunk_equals(hash, dst_hash)) + { + this->dst_matched = TRUE; + } + } + /* RFC4555 says we should also compare against IKE_SA_INIT + * NATD payloads, but this does not work: We are running + * there at port 500, but use 4500 afterwards... */ + if (message->get_exchange_type(message) == INFORMATIONAL && + this->initiator && !this->dst_matched) + { + this->mapping_changed = this->ike_sa->has_mapping_changed( + this->ike_sa, hash); + } + break; + } + case NAT_DETECTION_SOURCE_IP: + { + this->src_seen = TRUE; + if (!this->src_matched) + { + hash = notify->get_notification_data(notify); + DBG3(DBG_IKE, "received src_hash %B", &hash); + if (chunk_equals(hash, src_hash)) + { + this->src_matched = TRUE; + } + } + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); + + chunk_free(&src_hash); + chunk_free(&dst_hash); + + if (this->src_seen && this->dst_seen) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); + + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (this->dst_matched && this->src_matched && + config->force_encap(config)) + { + this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE); + } + } +} + +METHOD(task_t, process_i, status_t, + private_ike_natd_t *this, message_t *message) +{ + process_payloads(this, message); + + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY) || + /* if peer supports NAT-T, we switch to port 4500 even + * if no NAT is detected. can't be done later (when we would know + * whether the peer supports MOBIKE) because there would be no + * exchange to actually do the switch (other than a forced DPD). */ + (peer_cfg->use_mobike(peer_cfg) && + this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))) + { + this->ike_sa->float_ports(this->ike_sa); + } + } + + return SUCCESS; +} + +METHOD(task_t, build_i, status_t, + private_ike_natd_t *this, message_t *message) +{ + notify_payload_t *notify; + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + host_t *host; + + if (this->hasher == NULL) + { + DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); + return NEED_MORE; + } + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + + /* destination is always set */ + host = message->get_destination(message); + notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + + /* source may be any, we have 3 possibilities to get our source address: + * 1. It is defined in the config => use the one of the IKE_SA + * 2. We do a routing lookup in the kernel interface + * 3. Include all possbile addresses + */ + host = message->get_source(message); + if (!host->is_anyaddr(host) || ike_cfg->force_encap(ike_cfg)) + { /* 1. or if we force UDP encap, as it doesn't matter if it's %any */ + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + } + else + { + host = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, + this->ike_sa->get_other_host(this->ike_sa), NULL); + if (host) + { /* 2. */ + host->set_port(host, ike_cfg->get_my_port(ike_cfg)); + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + host->destroy(host); + } + else + { /* 3. */ + enumerator = hydra->kernel_interface->create_address_enumerator( + hydra->kernel_interface, ADDR_TYPE_REGULAR); + while (enumerator->enumerate(enumerator, (void**)&host)) + { + /* apply port 500 to host, but work on a copy */ + host = host->clone(host); + host->set_port(host, ike_cfg->get_my_port(ike_cfg)); + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); + host->destroy(host); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + } + enumerator->destroy(enumerator); + } + } + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_natd_t *this, message_t *message) +{ + notify_payload_t *notify; + host_t *me, *other; + + /* only add notifies on successful responses. */ + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_payload(message, SECURITY_ASSOCIATION) == NULL) + { + return SUCCESS; + } + + if (this->src_seen && this->dst_seen) + { + if (this->hasher == NULL) + { + DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); + return SUCCESS; + } + + /* initiator seems to support NAT detection, add response */ + me = message->get_source(message); + notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + other = message->get_destination(message); + notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other); + if (notify) + { + message->add_payload(message, (payload_t*)notify); + } + } + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_ike_natd_t *this, message_t *message) +{ + process_payloads(this, message); + + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_natd_t *this) +{ + return TASK_IKE_NATD; +} + +METHOD(task_t, migrate, void, + private_ike_natd_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->src_seen = FALSE; + this->dst_seen = FALSE; + this->src_matched = FALSE; + this->dst_matched = FALSE; + this->mapping_changed = FALSE; +} + +METHOD(task_t, destroy, void, + private_ike_natd_t *this) +{ + DESTROY_IF(this->hasher); + free(this); +} + +METHOD(ike_natd_t, has_mapping_changed, bool, + private_ike_natd_t *this) +{ + return this->mapping_changed; +} + +/* + * Described in header. + */ +ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_natd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .has_mapping_changed = _has_mapping_changed, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.h b/src/libcharon/sa/ikev2/tasks/ike_natd.h new file mode 100644 index 000000000..9c571b8e6 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_natd.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_natd ike_natd + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_NATD_H_ +#define IKE_NATD_H_ + +typedef struct ike_natd_t ike_natd_t; + +#include +#include +#include + +/** + * Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange. + */ +struct ike_natd_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Check if the NAT mapping has changed for our address. + * + * MOBIKE uses NAT payloads in DPD to detect changes in the NAT mappings. + * + * @return TRUE if mappings have changed + */ + bool (*has_mapping_changed)(ike_natd_t *this); +}; + +/** + * Create a new ike_natd task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_natd task to handle by the task_manager + */ +ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_NATD_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth.c b/src/libcharon/sa/ikev2/tasks/ike_reauth.c new file mode 100644 index 000000000..6f90339ea --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2006-2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_reauth.h" + +#include +#include + + +typedef struct private_ike_reauth_t private_ike_reauth_t; + +/** + * Private members of a ike_reauth_t task. + */ +struct private_ike_reauth_t { + + /** + * Public methods and task_t interface. + */ + ike_reauth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * reused ike_delete task + */ + ike_delete_t *ike_delete; +}; + +METHOD(task_t, build_i, status_t, + private_ike_reauth_t *this, message_t *message) +{ + return this->ike_delete->task.build(&this->ike_delete->task, message); +} + +METHOD(task_t, process_i, status_t, + private_ike_reauth_t *this, message_t *message) +{ + /* process delete response first */ + this->ike_delete->task.process(&this->ike_delete->task, message); + + /* reestablish the IKE_SA with all children */ + if (this->ike_sa->reestablish(this->ike_sa) != SUCCESS) + { + DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); + return FAILED; + } + + /* we always destroy the obsolete IKE_SA */ + return DESTROY_ME; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_reauth_t *this) +{ + return TASK_IKE_REAUTH; +} + +METHOD(task_t, migrate, void, + private_ike_reauth_t *this, ike_sa_t *ike_sa) +{ + this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa); + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_reauth_t *this) +{ + this->ike_delete->task.destroy(&this->ike_delete->task); + free(this); +} + +/* + * Described in header. + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) +{ + private_ike_reauth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .build = _build_i, + .process = _process_i, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_delete = ike_delete_create(ike_sa, TRUE), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth.h b/src/libcharon/sa/ikev2/tasks/ike_reauth.h new file mode 100644 index 000000000..781b463a7 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_reauth ike_reauth + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_REAUTH_H_ +#define IKE_REAUTH_H_ + +typedef struct ike_reauth_t ike_reauth_t; + +#include +#include +#include + +/** + * Task of type ike_reauth, reestablishes an IKE_SA. + */ +struct ike_reauth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_reauth task. + * + * This task is initiator only. + * + * @param ike_sa IKE_SA this task works for + * @return ike_reauth task to handle by the task_manager + */ +ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa); + +#endif /** IKE_REAUTH_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c new file mode 100644 index 000000000..c3c6cf00e --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_rekey.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct private_ike_rekey_t private_ike_rekey_t; + +/** + * Private members of a ike_rekey_t task. + */ +struct private_ike_rekey_t { + + /** + * Public methods and task_t interface. + */ + ike_rekey_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * New IKE_SA which replaces the current one + */ + ike_sa_t *new_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * the TASK_IKE_INIT task which is reused to simplify rekeying + */ + ike_init_t *ike_init; + + /** + * IKE_DELETE task to delete the old IKE_SA after rekeying was successful + */ + ike_delete_t *ike_delete; + + /** + * colliding task detected by the task manager + */ + task_t *collision; +}; + +/** + * Establish the new replacement IKE_SA + */ +static void establish_new(private_ike_rekey_t *this) +{ + if (this->new_sa) + { + this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); + DBG0(DBG_IKE, "IKE_SA %s[%d] rekeyed between %H[%Y]...%H[%Y]", + this->new_sa->get_name(this->new_sa), + this->new_sa->get_unique_id(this->new_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->new_sa->inherit(this->new_sa, this->ike_sa); + charon->bus->ike_rekey(charon->bus, this->ike_sa, this->new_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa); + this->new_sa = NULL; + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); + } +} + +METHOD(task_t, process_r_delete, status_t, + private_ike_rekey_t *this, message_t *message) +{ + establish_new(this); + return this->ike_delete->task.process(&this->ike_delete->task, message); +} + +METHOD(task_t, build_r_delete, status_t, + private_ike_rekey_t *this, message_t *message) +{ + return this->ike_delete->task.build(&this->ike_delete->task, message); +} + +METHOD(task_t, build_i_delete, status_t, + private_ike_rekey_t *this, message_t *message) +{ + /* update exchange type to INFORMATIONAL for the delete */ + message->set_exchange_type(message, INFORMATIONAL); + + return this->ike_delete->task.build(&this->ike_delete->task, message); +} + +METHOD(task_t, process_i_delete, status_t, + private_ike_rekey_t *this, message_t *message) +{ + return this->ike_delete->task.process(&this->ike_delete->task, message); +} + +METHOD(task_t, build_i, status_t, + private_ike_rekey_t *this, message_t *message) +{ + ike_version_t version; + peer_cfg_t *peer_cfg; + host_t *other_host; + + /* create new SA only on first try */ + if (this->new_sa == NULL) + { + version = this->ike_sa->get_version(this->ike_sa); + this->new_sa = charon->ike_sa_manager->checkout_new( + charon->ike_sa_manager, version, TRUE); + if (!this->new_sa) + { /* shouldn't happen */ + return FAILED; + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + other_host = this->ike_sa->get_other_host(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); + this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host)); + this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); + } + this->ike_init->task.build(&this->ike_init->task, message); + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_ike_rekey_t *this, message_t *message) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + child_sa_t *child_sa; + + if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING) + { + DBG1(DBG_IKE, "peer initiated rekeying, but we are deleting"); + return NEED_MORE; + } + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, (void**)&child_sa)) + { + switch (child_sa->get_state(child_sa)) + { + case CHILD_CREATED: + case CHILD_REKEYING: + case CHILD_DELETING: + /* we do not allow rekeying while we have children in-progress */ + DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open"); + enumerator->destroy(enumerator); + return NEED_MORE; + default: + break; + } + } + enumerator->destroy(enumerator); + + this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->ike_sa->get_version(this->ike_sa), FALSE); + if (!this->new_sa) + { /* shouldn't happen */ + return FAILED; + } + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); + this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa); + this->ike_init->task.process(&this->ike_init->task, message); + + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_ike_rekey_t *this, message_t *message) +{ + if (this->new_sa == NULL) + { + /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */ + message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); + return SUCCESS; + } + + if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED) + { + return SUCCESS; + } + + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); + + /* rekeying successful, delete the IKE_SA using a subtask */ + this->ike_delete = ike_delete_create(this->ike_sa, FALSE); + this->public.task.build = _build_r_delete; + this->public.task.process = _process_r_delete; + + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_ike_rekey_t *this, message_t *message) +{ + if (message->get_notify(message, NO_ADDITIONAL_SAS)) + { + DBG1(DBG_IKE, "peer seems to not support IKE rekeying, " + "starting reauthentication"); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + lib->processor->queue_job(lib->processor, + (job_t*)rekey_ike_sa_job_create( + this->ike_sa->get_id(this->ike_sa), TRUE)); + return SUCCESS; + } + + switch (this->ike_init->task.process(&this->ike_init->task, message)) + { + case FAILED: + /* rekeying failed, fallback to old SA */ + if (!(this->collision && ( + this->collision->get_type(this->collision) == TASK_IKE_DELETE || + this->collision->get_type(this->collision) == TASK_IKE_REAUTH))) + { + job_t *job; + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + job = (job_t*)rekey_ike_sa_job_create( + this->ike_sa->get_id(this->ike_sa), FALSE); + DBG1(DBG_IKE, "IKE_SA rekeying failed, " + "trying again in %d seconds", retry); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + lib->scheduler->schedule_job(lib->scheduler, job, retry); + } + return SUCCESS; + case NEED_MORE: + /* bad dh group, try again */ + this->ike_init->task.migrate(&this->ike_init->task, this->new_sa); + return NEED_MORE; + default: + break; + } + + /* check for collisions */ + if (this->collision && + this->collision->get_type(this->collision) == TASK_IKE_REKEY) + { + private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision; + + /* ike_init can be NULL, if child_sa is half-open */ + if (other->ike_init) + { + host_t *host; + chunk_t this_nonce, other_nonce; + + this_nonce = this->ike_init->get_lower_nonce(this->ike_init); + other_nonce = other->ike_init->get_lower_nonce(other->ike_init); + + /* if we have the lower nonce, delete rekeyed SA. If not, delete + * the redundant. */ + if (memcmp(this_nonce.ptr, other_nonce.ptr, + min(this_nonce.len, other_nonce.len)) > 0) + { + /* peer should delete this SA. Add a timeout just in case. */ + job_t *job = (job_t*)delete_ike_sa_job_create( + other->new_sa->get_id(other->new_sa), TRUE); + lib->scheduler->schedule_job(lib->scheduler, job, 10); + DBG1(DBG_IKE, "IKE_SA rekey collision won, waiting for delete"); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); + other->new_sa = NULL; + } + else + { + DBG1(DBG_IKE, "IKE_SA rekey collision lost, " + "deleting redundant IKE_SA"); + /* apply host for a proper delete */ + host = this->ike_sa->get_my_host(this->ike_sa); + this->new_sa->set_my_host(this->new_sa, host->clone(host)); + host = this->ike_sa->get_other_host(this->ike_sa); + this->new_sa->set_other_host(this->new_sa, host->clone(host)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + this->new_sa->set_state(this->new_sa, IKE_REKEYING); + if (this->new_sa->delete(this->new_sa) == DESTROY_ME) + { + this->new_sa->destroy(this->new_sa); + } + else + { + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, this->new_sa); + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); + } + this->new_sa = NULL; + establish_new(other); + return SUCCESS; + } + } + /* set threads active IKE_SA after checkin */ + charon->bus->set_sa(charon->bus, this->ike_sa); + } + + establish_new(this); + + /* rekeying successful, delete the IKE_SA using a subtask */ + this->ike_delete = ike_delete_create(this->ike_sa, TRUE); + this->public.task.build = _build_i_delete; + this->public.task.process = _process_i_delete; + + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_rekey_t *this) +{ + return TASK_IKE_REKEY; +} + +METHOD(ike_rekey_t, collide, void, + private_ike_rekey_t* this, task_t *other) +{ + DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, + TASK_IKE_REKEY, task_type_names, other->get_type(other)); + DESTROY_IF(this->collision); + this->collision = other; +} + +METHOD(task_t, migrate, void, + private_ike_rekey_t *this, ike_sa_t *ike_sa) +{ + if (this->ike_init) + { + this->ike_init->task.destroy(&this->ike_init->task); + } + if (this->ike_delete) + { + this->ike_delete->task.destroy(&this->ike_delete->task); + } + DESTROY_IF(this->new_sa); + DESTROY_IF(this->collision); + + this->collision = NULL; + this->ike_sa = ike_sa; + this->new_sa = NULL; + this->ike_init = NULL; + this->ike_delete = NULL; +} + +METHOD(task_t, destroy, void, + private_ike_rekey_t *this) +{ + if (this->ike_init) + { + this->ike_init->task.destroy(&this->ike_init->task); + } + if (this->ike_delete) + { + this->ike_delete->task.destroy(&this->ike_delete->task); + } + DESTROY_IF(this->new_sa); + DESTROY_IF(this->collision); + free(this); +} + +/* + * Described in header. + */ +ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_rekey_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .build = _build_r, + .process = _process_r, + .migrate = _migrate, + .destroy = _destroy, + }, + .collide = _collide, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.h b/src/libcharon/sa/ikev2/tasks/ike_rekey.h new file mode 100644 index 000000000..6a12e9034 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_rekey ike_rekey + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_REKEY_H_ +#define IKE_REKEY_H_ + +typedef struct ike_rekey_t ike_rekey_t; + +#include +#include +#include + +/** + * Task of type TASK_IKE_REKEY, rekey an established IKE_SA. + */ +struct ike_rekey_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Register a rekeying task which collides with this one. + * + * If two peers initiate rekeying at the same time, the collision must + * be handled gracefully. The task manager is aware of what exchanges + * are going on and notifies the outgoing task by passing the incoming. + * + * @param other incoming task + */ + void (*collide)(ike_rekey_t* this, task_t *other); +}; + +/** + * Create a new TASK_IKE_REKEY task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator, FALSE for responder + * @return TASK_IKE_REKEY task to handle by the task_manager + */ +ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_REKEY_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c new file mode 100644 index 000000000..2730f5876 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_vendor.h" + +#include +#include + +typedef struct private_ike_vendor_t private_ike_vendor_t; + +/** + * Private data of an ike_vendor_t object. + */ +struct private_ike_vendor_t { + + /** + * Public ike_vendor_t interface. + */ + ike_vendor_t public; + + /** + * Associated IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * Are we the inititator of this task + */ + bool initiator; +}; + +/** + * strongSwan specific vendor ID without version, MD5("strongSwan") + */ +static chunk_t strongswan_vid = chunk_from_chars( + 0x88,0x2f,0xe5,0x6d,0x6f,0xd2,0x0d,0xbc, + 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb +); + +METHOD(task_t, build, status_t, + private_ike_vendor_t *this, message_t *message) +{ + if (lib->settings->get_bool(lib->settings, + "%s.send_vendor_id", FALSE, charon->name)) + { + vendor_id_payload_t *vid; + + vid = vendor_id_payload_create_data(VENDOR_ID, + chunk_clone(strongswan_vid)); + message->add_payload(message, &vid->payload_interface); + } + + return this->initiator ? NEED_MORE : SUCCESS; +} + +METHOD(task_t, process, status_t, + private_ike_vendor_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == VENDOR_ID) + { + vendor_id_payload_t *vid; + chunk_t data; + + vid = (vendor_id_payload_t*)payload; + data = vid->get_data(vid); + + if (chunk_equals(data, strongswan_vid)) + { + DBG1(DBG_IKE, "received strongSwan vendor ID"); + this->ike_sa->enable_extension(this->ike_sa, EXT_STRONGSWAN); + } + else + { + DBG1(DBG_ENC, "received unknown vendor ID: %#B", &data); + } + } + } + enumerator->destroy(enumerator); + + return this->initiator ? SUCCESS : NEED_MORE; +} + +METHOD(task_t, migrate, void, + private_ike_vendor_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_vendor_t *this) +{ + return TASK_IKE_VENDOR; +} + +METHOD(task_t, destroy, void, + private_ike_vendor_t *this) +{ + free(this); +} + +/** + * See header + */ +ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_vendor_t *this; + + INIT(this, + .public = { + .task = { + .build = _build, + .process = _process, + .migrate = _migrate, + .get_type = _get_type, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_vendor.h b/src/libcharon/sa/ikev2/tasks/ike_vendor.h new file mode 100644 index 000000000..86c711636 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_vendor ike_vendor + * @{ @ingroup tasks_v2 + */ + +#ifndef IKE_VENDOR_H_ +#define IKE_VENDOR_H_ + +typedef struct ike_vendor_t ike_vendor_t; + +#include +#include +#include + +/** + * Vendor ID processing task. + */ +struct ike_vendor_t { + + /** + * Implements task interface. + */ + task_t task; +}; + +/** + * Create a ike_vendor instance. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + */ +ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_VENDOR_H_ @}*/ diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index d762fa34e..26c305f77 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Martin Willi + * Copyright (C) 2011 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,621 +15,112 @@ #include "keymat.h" -#include -#include +#include +#include -typedef struct private_keymat_t private_keymat_t; +static keymat_constructor_t keymat_v1_ctor = NULL, keymat_v2_ctor = NULL; /** - * Private data of an keymat_t object. + * See header */ -struct private_keymat_t { - - /** - * Public keymat_t interface. - */ - keymat_t public; - - /** - * IKE_SA Role, initiator or responder - */ - bool initiator; - - /** - * inbound AEAD - */ - aead_t *aead_in; - - /** - * outbound AEAD - */ - aead_t *aead_out; - - /** - * General purpose PRF - */ - prf_t *prf; - - /** - * Negotiated PRF algorithm - */ - pseudo_random_function_t prf_alg; - - /** - * Key to derive key material from for CHILD_SAs, rekeying - */ - chunk_t skd; - - /** - * Key to build outging authentication data (SKp) - */ - chunk_t skp_build; - - /** - * Key to verify incoming authentication data (SKp) - */ - chunk_t skp_verify; -}; +keymat_t *keymat_create(ike_version_t version, bool initiator) +{ + keymat_t *keymat = NULL; -typedef struct keylen_entry_t keylen_entry_t; + switch (version) + { + case IKEV1: +#ifdef USE_IKEV1 + keymat = keymat_v1_ctor ? keymat_v1_ctor(initiator) + : &keymat_v1_create(initiator)->keymat; +#endif + break; + case IKEV2: +#ifdef USE_IKEV2 + keymat = keymat_v2_ctor ? keymat_v2_ctor(initiator) + : &keymat_v2_create(initiator)->keymat; +#endif + break; + default: + break; + } + return keymat; +} /** * Implicit key length for an algorithm */ -struct keylen_entry_t { +typedef struct { /** IKEv2 algorithm identifier */ - int algo; + int alg; /** key length in bits */ int len; -}; - -#define END_OF_LIST -1 - -/** - * Keylen for encryption algos - */ -keylen_entry_t keylen_enc[] = { - {ENCR_DES, 64}, - {ENCR_3DES, 192}, - {END_OF_LIST, 0} -}; +} keylen_entry_t; /** - * Keylen for integrity algos + * See header. */ -keylen_entry_t keylen_int[] = { - {AUTH_HMAC_MD5_96, 128}, - {AUTH_HMAC_MD5_128, 128}, - {AUTH_HMAC_SHA1_96, 160}, - {AUTH_HMAC_SHA1_160, 160}, - {AUTH_HMAC_SHA2_256_96, 256}, - {AUTH_HMAC_SHA2_256_128, 256}, - {AUTH_HMAC_SHA2_384_192, 384}, - {AUTH_HMAC_SHA2_512_256, 512}, - {AUTH_AES_XCBC_96, 128}, - {END_OF_LIST, 0} -}; - -/** - * Lookup key length of an algorithm - */ -static int lookup_keylen(keylen_entry_t *list, int algo) +int keymat_get_keylen_encr(encryption_algorithm_t alg) { - while (list->algo != END_OF_LIST) + keylen_entry_t map[] = { + {ENCR_DES, 64}, + {ENCR_3DES, 192}, + }; + int i; + + for (i = 0; i < countof(map); i++) { - if (algo == list->algo) + if (map[i].alg == alg) { - return list->len; + return map[i].len; } - list++; } return 0; } -METHOD(keymat_t, create_dh, diffie_hellman_t*, - private_keymat_t *this, diffie_hellman_group_t group) -{ - return lib->crypto->create_dh(lib->crypto, group);; -} - /** - * Derive IKE keys for a combined AEAD algorithm + * See header. */ -static bool derive_ike_aead(private_keymat_t *this, u_int16_t alg, - u_int16_t key_size, prf_plus_t *prf_plus) +int keymat_get_keylen_integ(integrity_algorithm_t alg) { - aead_t *aead_i, *aead_r; - chunk_t key; - - /* SK_ei/SK_er used for encryption */ - aead_i = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); - aead_r = lib->crypto->create_aead(lib->crypto, alg, key_size / 8); - if (aead_i == NULL || aead_r == NULL) - { - DBG1(DBG_IKE, "%N %N (key size %d) not supported!", - transform_type_names, ENCRYPTION_ALGORITHM, - encryption_algorithm_names, alg, key_size); - return FALSE; - } - key_size = aead_i->get_key_size(aead_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - aead_i->set_key(aead_i, key); - chunk_clear(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_er secret %B", &key); - aead_r->set_key(aead_r, key); - chunk_clear(&key); - - if (this->initiator) - { - this->aead_in = aead_r; - this->aead_out = aead_i; - } - else - { - this->aead_in = aead_i; - this->aead_out = aead_r; + keylen_entry_t map[] = { + {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_MD5_128, 128}, + {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA1_160, 160}, + {AUTH_HMAC_SHA2_256_96, 256}, + {AUTH_HMAC_SHA2_256_128, 256}, + {AUTH_HMAC_SHA2_384_192, 384}, + {AUTH_HMAC_SHA2_512_256, 512}, + {AUTH_AES_XCBC_96, 128}, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].alg == alg) + { + return map[i].len; + } } - return TRUE; + return 0; } /** - * Derive IKE keys for traditional encryption and MAC algorithms + * See header. */ -static bool derive_ike_traditional(private_keymat_t *this, u_int16_t enc_alg, - u_int16_t enc_size, u_int16_t int_alg, prf_plus_t *prf_plus) +void keymat_register_constructor(ike_version_t version, + keymat_constructor_t create) { - crypter_t *crypter_i, *crypter_r; - signer_t *signer_i, *signer_r; - size_t key_size; - chunk_t key; - - /* SK_ai/SK_ar used for integrity protection */ - signer_i = lib->crypto->create_signer(lib->crypto, int_alg); - signer_r = lib->crypto->create_signer(lib->crypto, int_alg); - if (signer_i == NULL || signer_r == NULL) + switch (version) { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, INTEGRITY_ALGORITHM, - integrity_algorithm_names, int_alg); - return FALSE; - } - key_size = signer_i->get_key_size(signer_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ai secret %B", &key); - signer_i->set_key(signer_i, key); - chunk_clear(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ar secret %B", &key); - signer_r->set_key(signer_r, key); - chunk_clear(&key); - - /* SK_ei/SK_er used for encryption */ - crypter_i = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); - crypter_r = lib->crypto->create_crypter(lib->crypto, enc_alg, enc_size / 8); - if (crypter_i == NULL || crypter_r == NULL) - { - DBG1(DBG_IKE, "%N %N (key size %d) not supported!", - transform_type_names, ENCRYPTION_ALGORITHM, - encryption_algorithm_names, enc_alg, enc_size); - signer_i->destroy(signer_i); - signer_r->destroy(signer_r); - return FALSE; - } - key_size = crypter_i->get_key_size(crypter_i); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - crypter_i->set_key(crypter_i, key); - chunk_clear(&key); - - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_er secret %B", &key); - crypter_r->set_key(crypter_r, key); - chunk_clear(&key); - - if (this->initiator) - { - this->aead_in = aead_create(crypter_r, signer_r); - this->aead_out = aead_create(crypter_i, signer_i); - } - else - { - this->aead_in = aead_create(crypter_i, signer_i); - this->aead_out = aead_create(crypter_r, signer_r); - } - return TRUE; -} - -METHOD(keymat_t, derive_ike_keys, bool, - private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, - pseudo_random_function_t rekey_function, chunk_t rekey_skd) -{ - chunk_t skeyseed, key, secret, full_nonce, fixed_nonce, prf_plus_seed; - chunk_t spi_i, spi_r; - prf_plus_t *prf_plus; - u_int16_t alg, key_size, int_alg; - prf_t *rekey_prf = NULL; - - spi_i = chunk_alloca(sizeof(u_int64_t)); - spi_r = chunk_alloca(sizeof(u_int64_t)); - - if (dh->get_shared_secret(dh, &secret) != SUCCESS) - { - return FALSE; - } - - /* Create SAs general purpose PRF first, we may use it here */ - if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, PSEUDO_RANDOM_FUNCTION); - return FALSE; - } - this->prf_alg = alg; - this->prf = lib->crypto->create_prf(lib->crypto, alg); - if (this->prf == NULL) - { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, PSEUDO_RANDOM_FUNCTION, - pseudo_random_function_names, alg); - return FALSE; - } - DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret); - /* full nonce is used as seed for PRF+ ... */ - full_nonce = chunk_cat("cc", nonce_i, nonce_r); - /* but the PRF may need a fixed key which only uses the first bytes of - * the nonces. */ - switch (alg) - { - case PRF_AES128_XCBC: - /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does - * not and therefore fixed key semantics apply to XCBC for key - * derivation. */ - case PRF_CAMELLIA128_XCBC: - /* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we - * assume fixed key length. */ - key_size = this->prf->get_key_size(this->prf)/2; - nonce_i.len = min(nonce_i.len, key_size); - nonce_r.len = min(nonce_r.len, key_size); + case IKEV1: + keymat_v1_ctor = create; + break; + case IKEV2: + keymat_v2_ctor = create; break; default: - /* all other algorithms use variable key length, full nonce */ break; } - fixed_nonce = chunk_cat("cc", nonce_i, nonce_r); - *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id); - *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id); - prf_plus_seed = chunk_cat("ccc", full_nonce, spi_i, spi_r); - - /* KEYMAT = prf+ (SKEYSEED, Ni | Nr | SPIi | SPIr) - * - * if we are rekeying, SKEYSEED is built on another way - */ - if (rekey_function == PRF_UNDEFINED) /* not rekeying */ - { - /* SKEYSEED = prf(Ni | Nr, g^ir) */ - this->prf->set_key(this->prf, fixed_nonce); - this->prf->allocate_bytes(this->prf, secret, &skeyseed); - this->prf->set_key(this->prf, skeyseed); - prf_plus = prf_plus_create(this->prf, prf_plus_seed); - } - else - { - /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) - * use OLD SAs PRF functions for both prf_plus and prf */ - rekey_prf = lib->crypto->create_prf(lib->crypto, rekey_function); - if (!rekey_prf) - { - DBG1(DBG_IKE, "PRF of old SA %N not supported!", - pseudo_random_function_names, rekey_function); - chunk_free(&full_nonce); - chunk_free(&fixed_nonce); - chunk_clear(&prf_plus_seed); - return FALSE; - } - secret = chunk_cat("mc", secret, full_nonce); - rekey_prf->set_key(rekey_prf, rekey_skd); - rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed); - rekey_prf->set_key(rekey_prf, skeyseed); - prf_plus = prf_plus_create(rekey_prf, prf_plus_seed); - } - DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); - - chunk_clear(&skeyseed); - chunk_clear(&secret); - chunk_free(&full_nonce); - chunk_free(&fixed_nonce); - chunk_clear(&prf_plus_seed); - - /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ - - /* SK_d is used for generating CHILD_SA key mat => store for later use */ - key_size = this->prf->get_key_size(this->prf); - prf_plus->allocate_bytes(prf_plus, key_size, &this->skd); - DBG4(DBG_IKE, "Sk_d secret %B", &this->skd); - - if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, ENCRYPTION_ALGORITHM); - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - - if (encryption_algorithm_is_aead(alg)) - { - if (!derive_ike_aead(this, alg, key_size, prf_plus)) - { - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - } - else - { - if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, - &int_alg, NULL)) - { - DBG1(DBG_IKE, "no %N selected", - transform_type_names, INTEGRITY_ALGORITHM); - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - if (!derive_ike_traditional(this, alg, key_size, int_alg, prf_plus)) - { - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - return FALSE; - } - } - - /* SK_pi/SK_pr used for authentication => stored for later */ - key_size = this->prf->get_key_size(this->prf); - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_pi secret %B", &key); - if (this->initiator) - { - this->skp_build = key; - } - else - { - this->skp_verify = key; - } - prf_plus->allocate_bytes(prf_plus, key_size, &key); - DBG4(DBG_IKE, "Sk_pr secret %B", &key); - if (this->initiator) - { - this->skp_verify = key; - } - else - { - this->skp_build = key; - } - - /* all done, prf_plus not needed anymore */ - prf_plus->destroy(prf_plus); - DESTROY_IF(rekey_prf); - - return TRUE; -} - -METHOD(keymat_t, derive_child_keys, bool, - private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r) -{ - u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; - chunk_t seed, secret = chunk_empty; - prf_plus_t *prf_plus; - - if (dh) - { - if (dh->get_shared_secret(dh, &secret) != SUCCESS) - { - return FALSE; - } - DBG4(DBG_CHD, "DH secret %B", &secret); - } - seed = chunk_cata("mcc", secret, nonce_i, nonce_r); - DBG4(DBG_CHD, "seed %B", &seed); - - if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, - &enc_alg, &enc_size)) - { - DBG2(DBG_CHD, " using %N for encryption", - encryption_algorithm_names, enc_alg); - - if (!enc_size) - { - enc_size = lookup_keylen(keylen_enc, enc_alg); - } - if (enc_alg != ENCR_NULL && !enc_size) - { - DBG1(DBG_CHD, "no keylength defined for %N", - encryption_algorithm_names, enc_alg); - return FALSE; - } - /* to bytes */ - enc_size /= 8; - - /* CCM/GCM/CTR/GMAC needs additional bytes */ - switch (enc_alg) - { - case ENCR_AES_CCM_ICV8: - case ENCR_AES_CCM_ICV12: - case ENCR_AES_CCM_ICV16: - case ENCR_CAMELLIA_CCM_ICV8: - case ENCR_CAMELLIA_CCM_ICV12: - case ENCR_CAMELLIA_CCM_ICV16: - enc_size += 3; - break; - case ENCR_AES_GCM_ICV8: - case ENCR_AES_GCM_ICV12: - case ENCR_AES_GCM_ICV16: - case ENCR_AES_CTR: - case ENCR_NULL_AUTH_AES_GMAC: - enc_size += 4; - break; - default: - break; - } - } - - if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, - &int_alg, &int_size)) - { - DBG2(DBG_CHD, " using %N for integrity", - integrity_algorithm_names, int_alg); - - if (!int_size) - { - int_size = lookup_keylen(keylen_int, int_alg); - } - if (!int_size) - { - DBG1(DBG_CHD, "no keylength defined for %N", - integrity_algorithm_names, int_alg); - return FALSE; - } - /* to bytes */ - int_size /= 8; - } - - this->prf->set_key(this->prf, this->skd); - prf_plus = prf_plus_create(this->prf, seed); - - prf_plus->allocate_bytes(prf_plus, enc_size, encr_i); - prf_plus->allocate_bytes(prf_plus, int_size, integ_i); - prf_plus->allocate_bytes(prf_plus, enc_size, encr_r); - prf_plus->allocate_bytes(prf_plus, int_size, integ_r); - - prf_plus->destroy(prf_plus); - - if (enc_size) - { - DBG4(DBG_CHD, "encryption initiator key %B", encr_i); - DBG4(DBG_CHD, "encryption responder key %B", encr_r); - } - if (int_size) - { - DBG4(DBG_CHD, "integrity initiator key %B", integ_i); - DBG4(DBG_CHD, "integrity responder key %B", integ_r); - } - return TRUE; -} - -METHOD(keymat_t, get_skd, pseudo_random_function_t, - private_keymat_t *this, chunk_t *skd) -{ - *skd = this->skd; - return this->prf_alg; -} - -METHOD(keymat_t, get_aead, aead_t*, - private_keymat_t *this, bool in) -{ - return in ? this->aead_in : this->aead_out; -} - -METHOD(keymat_t, get_auth_octets, chunk_t, - private_keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, char reserved[3]) -{ - chunk_t chunk, idx, octets; - chunk_t skp; - - skp = verify ? this->skp_verify : this->skp_build; - - chunk = chunk_alloca(4); - chunk.ptr[0] = id->get_type(id); - memcpy(chunk.ptr + 1, reserved, 3); - idx = chunk_cata("cc", chunk, id->get_encoding(id)); - - DBG3(DBG_IKE, "IDx' %B", &idx); - DBG3(DBG_IKE, "SK_p %B", &skp); - this->prf->set_key(this->prf, skp); - this->prf->allocate_bytes(this->prf, idx, &chunk); - - octets = chunk_cat("ccm", ike_sa_init, nonce, chunk); - DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", &octets); - return octets; } - -/** - * Key pad for the AUTH method SHARED_KEY_MESSAGE_INTEGRITY_CODE. - */ -#define IKEV2_KEY_PAD "Key Pad for IKEv2" -#define IKEV2_KEY_PAD_LENGTH 17 - -METHOD(keymat_t, get_psk_sig, chunk_t, - private_keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) -{ - chunk_t key_pad, key, sig, octets; - - if (!secret.len) - { /* EAP uses SK_p if no MSK has been established */ - secret = verify ? this->skp_verify : this->skp_build; - } - octets = get_auth_octets(this, verify, ike_sa_init, nonce, id, reserved); - /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), ) */ - key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH); - this->prf->set_key(this->prf, secret); - this->prf->allocate_bytes(this->prf, key_pad, &key); - this->prf->set_key(this->prf, key); - this->prf->allocate_bytes(this->prf, octets, &sig); - DBG4(DBG_IKE, "secret %B", &secret); - DBG4(DBG_IKE, "prf(secret, keypad) %B", &key); - DBG3(DBG_IKE, "AUTH = prf(prf(secret, keypad), octets) %B", &sig); - chunk_free(&octets); - chunk_free(&key); - - return sig; -} - -METHOD(keymat_t, destroy, void, - private_keymat_t *this) -{ - DESTROY_IF(this->aead_in); - DESTROY_IF(this->aead_out); - DESTROY_IF(this->prf); - chunk_clear(&this->skd); - chunk_clear(&this->skp_verify); - chunk_clear(&this->skp_build); - free(this); -} - -/** - * See header - */ -keymat_t *keymat_create(bool initiator) -{ - private_keymat_t *this; - - INIT(this, - .public = { - .create_dh = _create_dh, - .derive_ike_keys = _derive_ike_keys, - .derive_child_keys = _derive_child_keys, - .get_skd = _get_skd, - .get_aead = _get_aead, - .get_auth_octets = _get_auth_octets, - .get_psk_sig = _get_psk_sig, - .destroy = _destroy, - }, - .initiator = initiator, - .prf_alg = PRF_UNDEFINED, - ); - - return &this->public; -} - diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 6c2b5d4b5..02db5ca58 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -21,20 +21,36 @@ #ifndef KEYMAT_H_ #define KEYMAT_H_ +typedef struct keymat_t keymat_t; + #include #include #include #include #include +#include #include -typedef struct keymat_t keymat_t; +/** + * Constructor function for custom keymat implementations + * + * @param initiator TRUE if the keymat is used as initiator + * @return keymat_t implementation + */ +typedef keymat_t* (*keymat_constructor_t)(bool initiator); /** * Derivation an management of sensitive keying material. */ struct keymat_t { + /** + * Get IKE version of this keymat. + * + * @return IKEV1 for keymat_v1_t, IKEV2 for keymat_v2_t + */ + ike_version_t (*get_version)(keymat_t *this); + /** * Create a diffie hellman object for key agreement. * @@ -50,58 +66,18 @@ struct keymat_t { * @param group diffie hellman group * @return DH object, NULL if group not supported */ - diffie_hellman_t* (*create_dh)(keymat_t *this, diffie_hellman_group_t group); + diffie_hellman_t* (*create_dh)(keymat_t *this, + diffie_hellman_group_t group); /** - * Derive keys for the IKE_SA. + * Create a nonce generator object. * - * These keys are not handed out, but are used by the associated signers, - * crypters and authentication functions. + * The nonce generator can be used to create nonces needed during IKE/CHILD + * SA establishment or rekeying. * - * @param proposal selected algorithms - * @param dh diffie hellman key allocated by create_dh() - * @param nonce_i initiators nonce value - * @param nonce_r responders nonce value - * @param id IKE_SA identifier - * @param rekey_prf PRF of old SA if rekeying, PRF_UNDEFINED otherwise - * @param rekey_sdk SKd of old SA if rekeying - * @return TRUE on success + * @return nonce generator object */ - bool (*derive_ike_keys)(keymat_t *this, proposal_t *proposal, - diffie_hellman_t *dh, chunk_t nonce_i, - chunk_t nonce_r, ike_sa_id_t *id, - pseudo_random_function_t rekey_function, - chunk_t rekey_skd); - /** - * Derive keys for a CHILD_SA. - * - * The keys for the CHILD_SA are allocated in the integ and encr chunks. - * An implementation might hand out encrypted keys only, which are - * decrypted in the kernel before use. - * If no PFS is used for the CHILD_SA, dh can be NULL. - * - * @param proposal selected algorithms - * @param dh diffie hellman key allocated by create_dh(), or NULL - * @param nonce_i initiators nonce value - * @param nonce_r responders nonce value - * @param encr_i chunk to write initiators encryption key to - * @param integ_i chunk to write initiators integrity key to - * @param encr_r chunk to write responders encryption key to - * @param integ_r chunk to write responders integrity key to - * @return TRUE on success - */ - bool (*derive_child_keys)(keymat_t *this, - proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, - chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r); - /** - * Get SKd to pass to derive_ikey_keys() during rekeying. - * - * @param skd chunk to write SKd to (internal data) - * @return PRF function to derive keymat - */ - pseudo_random_function_t (*get_skd)(keymat_t *this, chunk_t *skd); + nonce_gen_t* (*create_nonce_gen)(keymat_t *this); /* * Get a AEAD transform to en-/decrypt and sign/verify IKE messages. @@ -111,41 +87,6 @@ struct keymat_t { */ aead_t* (*get_aead)(keymat_t *this, bool in); - /** - * Generate octets to use for authentication procedure (RFC4306 2.15). - * - * This method creates the plain octets and is usually signed by a private - * key. PSK and EAP authentication include a secret into the data, use - * the get_psk_sig() method instead. - * - * @param verify TRUE to create for verfification, FALSE to sign - * @param ike_sa_init encoded ike_sa_init message - * @param nonce nonce value - * @param id identity - * @param reserved reserved bytes of id_payload - * @return authentication octets - */ - chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, - char reserved[3]); - /** - * Build the shared secret signature used for PSK and EAP authentication. - * - * This method wraps the get_auth_octets() method and additionally - * includes the secret into the signature. If no secret is given, SK_p is - * used as secret (used for EAP methods without MSK). - * - * @param verify TRUE to create for verfification, FALSE to sign - * @param ike_sa_init encoded ike_sa_init message - * @param nonce nonce value - * @param secret optional secret to include into signature - * @param id identity - * @param reserved reserved bytes of id_payload - * @return signature octets - */ - chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, - identification_t *id, char reserved[3]); /** * Destroy a keymat_t. */ @@ -153,11 +94,37 @@ struct keymat_t { }; /** - * Create a keymat instance. + * Create the appropriate keymat_t implementation based on the IKE version. + * + * @param version requested IKE version + * @param initiator TRUE if we are initiator + * @return keymat_t implmenetation + */ +keymat_t *keymat_create(ike_version_t version, bool initiator); + +/** + * Look up the key length of an encryption algorithm. + * + * @param alg algorithm to get key length for + * @return key length in bits + */ +int keymat_get_keylen_encr(encryption_algorithm_t alg); + +/** + * Look up the key length of an integrity algorithm. + * + * @param alg algorithm to get key length for + * @return key length in bits + */ +int keymat_get_keylen_integ(integrity_algorithm_t alg); + +/** + * Register keymat_t constructor for given IKE version. * - * @param initiator TRUE if we are the initiator - * @return keymat instance + * @param version IKE version of given keymat constructor + * @param create keymat constructor function, NULL to unregister */ -keymat_t *keymat_create(bool initiator); +void keymat_register_constructor(ike_version_t version, + keymat_constructor_t create); #endif /** KEYMAT_H_ @}*/ diff --git a/src/libcharon/sa/mediation_manager.c b/src/libcharon/sa/mediation_manager.c deleted file mode 100644 index 60eeb5d4b..000000000 --- a/src/libcharon/sa/mediation_manager.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2007 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "mediation_manager.h" - -#include -#include -#include -#include - -typedef struct peer_t peer_t; - -/** - * An entry in the linked list. - */ -struct peer_t { - /** id of the peer */ - identification_t *id; - - /** sa id of the peer, NULL if offline */ - ike_sa_id_t *ike_sa_id; - - /** list of peer ids that reuested this peer */ - linked_list_t *requested_by; -}; - -/** - * Implementation of peer_t.destroy. - */ -static void peer_destroy(peer_t *this) -{ - DESTROY_IF(this->id); - DESTROY_IF(this->ike_sa_id); - this->requested_by->destroy_offset(this->requested_by, - offsetof(identification_t, destroy)); - free(this); -} - -/** - * Creates a new entry for the list. - */ -static peer_t *peer_create(identification_t *id, ike_sa_id_t* ike_sa_id) -{ - peer_t *this; - INIT(this, - .id = id->clone(id), - .ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL, - .requested_by = linked_list_create(), - ); - return this; -} - -typedef struct private_mediation_manager_t private_mediation_manager_t; - -/** - * Additional private members of mediation_manager_t. - */ -struct private_mediation_manager_t { - /** - * Public interface of mediation_manager_t. - */ - mediation_manager_t public; - - /** - * Lock for exclusivly accessing the manager. - */ - mutex_t *mutex; - - /** - * Linked list with state entries. - */ - linked_list_t *peers; -}; - -/** - * Registers a peer's ID at another peer, if it is not yet registered - */ -static void register_peer(peer_t *peer, identification_t *peer_id) -{ - enumerator_t *enumerator; - identification_t *current; - - enumerator = peer->requested_by->create_enumerator(peer->requested_by); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - if (peer_id->equals(peer_id, current)) - { - enumerator->destroy(enumerator); - return; - } - } - enumerator->destroy(enumerator); - - peer->requested_by->insert_last(peer->requested_by, - peer_id->clone(peer_id)); -} - -/** - * Get a peer_t object by a peer's id - */ -static status_t get_peer_by_id(private_mediation_manager_t *this, - identification_t *id, peer_t **peer) -{ - enumerator_t *enumerator; - peer_t *current; - status_t status = NOT_FOUND; - - enumerator = this->peers->create_enumerator(this->peers); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - if (id->equals(id, current->id)) - { - if (peer) - { - *peer = current; - } - status = SUCCESS; - break; - } - } - enumerator->destroy(enumerator); - - return status; -} - -/** - * Check if a given peer is registered at other peers. If so, remove it there - * and then remove peers completely that are not online and have no registered - * peers. - */ -static void unregister_peer(private_mediation_manager_t *this, - identification_t *peer_id) -{ - enumerator_t *enumerator, *enumerator_r; - peer_t *peer; - identification_t *registered; - - enumerator = this->peers->create_enumerator(this->peers); - while (enumerator->enumerate(enumerator, (void**)&peer)) - { - enumerator_r = peer->requested_by->create_enumerator(peer->requested_by); - while (enumerator_r->enumerate(enumerator_r, (void**)®istered)) - { - if (peer_id->equals(peer_id, registered)) - { - peer->requested_by->remove_at(peer->requested_by, enumerator_r); - registered->destroy(registered); - break; - } - } - enumerator_r->destroy(enumerator_r); - - if (!peer->ike_sa_id && - !peer->requested_by->get_count(peer->requested_by)) - { - this->peers->remove_at(this->peers, enumerator); - peer_destroy(peer); - break; - } - } - enumerator->destroy(enumerator); -} - -METHOD(mediation_manager_t, remove_sa, void, - private_mediation_manager_t *this, ike_sa_id_t *ike_sa_id) -{ - enumerator_t *enumerator; - peer_t *peer; - - this->mutex->lock(this->mutex); - - enumerator = this->peers->create_enumerator(this->peers); - while (enumerator->enumerate(enumerator, (void**)&peer)) - { - if (ike_sa_id->equals(ike_sa_id, peer->ike_sa_id)) - { - this->peers->remove_at(this->peers, enumerator); - - unregister_peer(this, peer->id); - - peer_destroy(peer); - break; - } - } - enumerator->destroy(enumerator); - - this->mutex->unlock(this->mutex); -} - -METHOD(mediation_manager_t, update_sa_id, void, - private_mediation_manager_t *this, identification_t *peer_id, - ike_sa_id_t *ike_sa_id) -{ - enumerator_t *enumerator; - peer_t *peer; - bool found = FALSE; - - this->mutex->lock(this->mutex); - - enumerator = this->peers->create_enumerator(this->peers); - while (enumerator->enumerate(enumerator, (void**)&peer)) - { - if (peer_id->equals(peer_id, peer->id)) - { - DESTROY_IF(peer->ike_sa_id); - found = TRUE; - break; - } - } - enumerator->destroy(enumerator); - - if (!found) - { - DBG2(DBG_IKE, "adding peer '%Y'", peer_id); - peer = peer_create(peer_id, NULL); - this->peers->insert_last(this->peers, peer); - } - - DBG2(DBG_IKE, "changing registered IKE_SA ID of peer '%Y'", peer_id); - peer->ike_sa_id = ike_sa_id ? ike_sa_id->clone(ike_sa_id) : NULL; - - /* send callbacks to registered peers */ - identification_t *requester; - while(peer->requested_by->remove_last(peer->requested_by, - (void**)&requester) == SUCCESS) - { - job_t *job = (job_t*)mediation_callback_job_create(requester, peer_id); - lib->processor->queue_job(lib->processor, job); - requester->destroy(requester); - } - - this->mutex->unlock(this->mutex); -} - -METHOD(mediation_manager_t, check, ike_sa_id_t*, - private_mediation_manager_t *this, identification_t *peer_id) -{ - peer_t *peer; - ike_sa_id_t *ike_sa_id; - - this->mutex->lock(this->mutex); - - if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) - { - this->mutex->unlock(this->mutex); - return NULL; - } - - ike_sa_id = peer->ike_sa_id; - - this->mutex->unlock(this->mutex); - - return ike_sa_id; -} - -METHOD(mediation_manager_t, check_and_register, ike_sa_id_t*, - private_mediation_manager_t *this, identification_t *peer_id, - identification_t *requester) -{ - peer_t *peer; - ike_sa_id_t *ike_sa_id; - - this->mutex->lock(this->mutex); - - if (get_peer_by_id(this, peer_id, &peer) != SUCCESS) - { - DBG2(DBG_IKE, "adding peer %Y", peer_id); - peer = peer_create(peer_id, NULL); - this->peers->insert_last(this->peers, peer); - } - - if (!peer->ike_sa_id) - { - /* the peer is not online */ - DBG2(DBG_IKE, "requested peer '%Y' is offline, registering peer '%Y'", - peer_id, requester); - register_peer(peer, requester); - this->mutex->unlock(this->mutex); - return NULL; - } - - ike_sa_id = peer->ike_sa_id; - - this->mutex->unlock(this->mutex); - - return ike_sa_id; -} - -METHOD(mediation_manager_t, destroy, void, - private_mediation_manager_t *this) -{ - this->mutex->lock(this->mutex); - - this->peers->destroy_function(this->peers, (void*)peer_destroy); - - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); - free(this); -} - -/* - * Described in header. - */ -mediation_manager_t *mediation_manager_create() -{ - private_mediation_manager_t *this; - - INIT(this, - .public = { - .destroy = _destroy, - .remove = _remove_sa, - .update_sa_id = _update_sa_id, - .check = _check, - .check_and_register = _check_and_register, - }, - .peers = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - ); - return &this->public; -} diff --git a/src/libcharon/sa/mediation_manager.h b/src/libcharon/sa/mediation_manager.h deleted file mode 100644 index 31a16f69c..000000000 --- a/src/libcharon/sa/mediation_manager.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2007 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup mediation_manager mediation_manager - * @{ @ingroup sa - */ - -#ifndef MEDIATION_MANAGER_H_ -#define MEDIATION_MANAGER_H_ - -typedef struct mediation_manager_t mediation_manager_t; - -#include -#include - -/** - * The mediation manager is responsible for managing currently online - * peers and registered requests for offline peers on the mediation server. - */ -struct mediation_manager_t { - - /** - * Remove the IKE_SA of a peer. - * - * @param ike_sa_id the IKE_SA ID of the peer's SA - */ - void (*remove) (mediation_manager_t* this, ike_sa_id_t *ike_sa_id); - - /** - * Update the ike_sa_id that is assigned to a peer's ID. If the peer - * is new, it gets a new record assigned. - * - * @param peer_id the peer's ID - * @param ike_sa_id the IKE_SA ID of the peer's SA - */ - void (*update_sa_id) (mediation_manager_t* this, identification_t *peer_id, - ike_sa_id_t *ike_sa_id); - - /** - * Checks if a specific peer is online. - * - * @param peer_id the peer's ID - * @returns - * - IKE_SA ID of the peer's SA. - * - NULL, if the peer is not online. - */ - ike_sa_id_t* (*check) (mediation_manager_t* this, - identification_t *peer_id); - - /** - * Checks if a specific peer is online and registers the requesting - * peer if it is not. - * - * @param peer_id the peer's ID - * @param requester the requesters ID - * @returns - * - IKE_SA ID of the peer's SA. - * - NULL, if the peer is not online. - */ - ike_sa_id_t* (*check_and_register) (mediation_manager_t* this, - identification_t *peer_id, - identification_t *requester); - - /** - * Destroys the manager with all data. - */ - void (*destroy) (mediation_manager_t *this); -}; - -/** - * Create a manager. - * - * @returns mediation_manager_t object - */ -mediation_manager_t *mediation_manager_create(void); - -#endif /** MEDIATION_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/shunt_manager.c b/src/libcharon/sa/shunt_manager.c index 52b2ecd62..5af43fb91 100644 --- a/src/libcharon/sa/shunt_manager.c +++ b/src/libcharon/sa/shunt_manager.c @@ -206,6 +206,7 @@ METHOD(shunt_manager_t, uninstall, bool, return FALSE; } uninstall_shunt_policy(child); + child->destroy(child); return TRUE; } diff --git a/src/libcharon/sa/task.c b/src/libcharon/sa/task.c new file mode 100644 index 000000000..4336b23ff --- /dev/null +++ b/src/libcharon/sa/task.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "task.h" + +ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, + "IKE_INIT", + "IKE_NATD", + "IKE_MOBIKE", + "IKE_AUTH", + "IKE_AUTH_LIFETIME", + "IKE_CERT_PRE", + "IKE_CERT_POST", + "IKE_CONFIG", + "IKE_REKEY", + "IKE_REAUTH", + "IKE_DELETE", + "IKE_DPD", + "IKE_VENDOR", +#ifdef ME + "IKE_ME", +#endif /* ME */ + "CHILD_CREATE", + "CHILD_DELETE", + "CHILD_REKEY", + "MAIN_MODE", + "AGGRESSIVE_MODE", + "INFORMATIONAL", + "ISAKMP_DELETE", + "XAUTH", + "MODE_CONFIG", + "QUICK_MODE", + "QUICK_DELETE", + "ISAKMP_VENDOR", + "ISAKMP_NATD", + "ISAKMP_DPD", + "ISAKMP_CERT_PRE", + "ISAKMP_CERT_POST", +); diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h new file mode 100644 index 000000000..c37221a77 --- /dev/null +++ b/src/libcharon/sa/task.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup task task + * @{ @ingroup sa + */ + +#ifndef TASK_H_ +#define TASK_H_ + +typedef enum task_type_t task_type_t; +typedef struct task_t task_t; + +#include +#include +#include + +/** + * Different kinds of tasks. + */ +enum task_type_t { + /** establish an unauthenticated IKE_SA */ + TASK_IKE_INIT, + /** detect NAT situation */ + TASK_IKE_NATD, + /** handle MOBIKE stuff */ + TASK_IKE_MOBIKE, + /** authenticate the initiated IKE_SA */ + TASK_IKE_AUTH, + /** AUTH_LIFETIME negotiation, RFC4478 */ + TASK_IKE_AUTH_LIFETIME, + /** certificate processing before authentication (certreqs, cert parsing) */ + TASK_IKE_CERT_PRE, + /** certificate processing after authentication (certs payload generation) */ + TASK_IKE_CERT_POST, + /** Configuration payloads, virtual IP and such */ + TASK_IKE_CONFIG, + /** rekey an IKE_SA */ + TASK_IKE_REKEY, + /** reestablish a complete IKE_SA */ + TASK_IKE_REAUTH, + /** delete an IKE_SA */ + TASK_IKE_DELETE, + /** liveness check */ + TASK_IKE_DPD, + /** Vendor ID processing */ + TASK_IKE_VENDOR, +#ifdef ME + /** handle ME stuff */ + TASK_IKE_ME, +#endif /* ME */ + /** establish a CHILD_SA within an IKE_SA */ + TASK_CHILD_CREATE, + /** delete an established CHILD_SA */ + TASK_CHILD_DELETE, + /** rekey an CHILD_SA */ + TASK_CHILD_REKEY, + /** IKEv1 main mode */ + TASK_MAIN_MODE, + /** IKEv1 aggressive mode */ + TASK_AGGRESSIVE_MODE, + /** IKEv1 informational exchange */ + TASK_INFORMATIONAL, + /** IKEv1 delete using an informational */ + TASK_ISAKMP_DELETE, + /** IKEv1 XAUTH authentication */ + TASK_XAUTH, + /** IKEv1 Mode Config */ + TASK_MODE_CONFIG, + /** IKEv1 quick mode */ + TASK_QUICK_MODE, + /** IKEv1 delete of a quick mode SA */ + TASK_QUICK_DELETE, + /** IKEv1 vendor ID payload handling */ + TASK_ISAKMP_VENDOR, + /** IKEv1 NAT detection */ + TASK_ISAKMP_NATD, + /** IKEv1 DPD */ + TASK_ISAKMP_DPD, + /** IKEv1 pre-authentication certificate handling */ + TASK_ISAKMP_CERT_PRE, + /** IKEv1 post-authentication certificate handling */ + TASK_ISAKMP_CERT_POST, +}; + +/** + * enum names for task_type_t. + */ +extern enum_name_t *task_type_names; + +/** + * Interface for a task, an operation handled within exchanges. + * + * A task is an elemantary operation. It may be handled by a single or by + * multiple exchanges. An exchange may even complete multiple tasks. + * A task has a build() and an process() operation. The build() operation + * creates payloads and adds it to the message. The process() operation + * inspects a message and handles its payloads. An initiator of an exchange + * first calls build() to build the request, and processes the response message + * with the process() method. + * A responder does the opposite; it calls process() first to handle an incoming + * request and secondly calls build() to build an appropriate response. + * Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates + * that the task completed, even when the task completed unsuccessfully. The + * manager then removes the task from the list. A NEED_MORE is returned when + * the task needs further build()/process() calls to complete, the manager + * leaves the taks in the queue. A returned FAILED indicates a critical failure. + * The manager closes the IKE_SA whenever a task returns FAILED. + */ +struct task_t { + + /** + * Build a request or response message for this task. + * + * @param message message to add payloads to + * @return + * - FAILED if a critical error occurred + * - DESTROY_ME if IKE_SA has been properly deleted + * - NEED_MORE if another call to build/process needed + * - ALREADY_DONE to cancel task processing + * - SUCCESS if task completed + */ + status_t (*build) (task_t *this, message_t *message); + + /** + * Process a request or response message for this task. + * + * @param message message to read payloads from + * @return + * - FAILED if a critical error occurred + * - DESTROY_ME if IKE_SA has been properly deleted + * - NEED_MORE if another call to build/process needed + * - ALREADY_DONE to cancel task processing + * - SUCCESS if task completed + */ + status_t (*process) (task_t *this, message_t *message); + + /** + * Get the type of the task implementation. + */ + task_type_t (*get_type) (task_t *this); + + /** + * Migrate a task to a new IKE_SA. + * + * After migrating a task, it goes back to a state where it can be + * used again to initate an exchange. This is useful when a task + * has to get migrated to a new IKE_SA. + * A special usage is when a INVALID_KE_PAYLOAD is received. A call + * to reset resets the task, but uses another DH group for the next + * try. + * The ike_sa is the new IKE_SA this task belongs to and operates on. + * + * @param ike_sa new IKE_SA this task works for + */ + void (*migrate) (task_t *this, ike_sa_t *ike_sa); + + /** + * Destroys a task_t object. + */ + void (*destroy) (task_t *this); +}; + +#endif /** TASK_H_ @}*/ diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index 022a5e3d6..c42008ba9 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2007-2010 Martin Willi + * Copyright (C) 2011 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,1135 +15,29 @@ #include "task_manager.h" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ME -#include -#endif - -typedef struct exchange_t exchange_t; +#include +#include /** - * An exchange in the air, used do detect and handle retransmission + * See header */ -struct exchange_t { - - /** - * Message ID used for this transaction - */ - u_int32_t mid; - - /** - * generated packet for retransmission - */ - packet_t *packet; -}; - -typedef struct private_task_manager_t private_task_manager_t; - -/** - * private data of the task manager - */ -struct private_task_manager_t { - - /** - * public functions - */ - task_manager_t public; - - /** - * associated IKE_SA we are serving - */ - ike_sa_t *ike_sa; - - /** - * Exchange we are currently handling as responder - */ - struct { - /** - * Message ID of the exchange - */ - u_int32_t mid; - - /** - * packet for retransmission - */ - packet_t *packet; - - } responding; - - /** - * Exchange we are currently handling as initiator - */ - struct { - /** - * Message ID of the exchange - */ - u_int32_t mid; - - /** - * how many times we have retransmitted so far - */ - u_int retransmitted; - - /** - * packet for retransmission - */ - packet_t *packet; - - /** - * type of the initated exchange - */ - exchange_type_t type; - - } initiating; - - /** - * List of queued tasks not yet in action - */ - linked_list_t *queued_tasks; - - /** - * List of active tasks, initiated by ourselve - */ - linked_list_t *active_tasks; - - /** - * List of tasks initiated by peer - */ - linked_list_t *passive_tasks; - - /** - * the task manager has been reset - */ - bool reset; - - /** - * Number of times we retransmit messages before giving up - */ - u_int retransmit_tries; - - /** - * Retransmission timeout - */ - double retransmit_timeout; - - /** - * Base to calculate retransmission timeout - */ - double retransmit_base; -}; - -/** - * flush all tasks in the task manager - */ -static void flush(private_task_manager_t *this) -{ - this->passive_tasks->destroy_offset(this->passive_tasks, - offsetof(task_t, destroy)); - this->passive_tasks = linked_list_create(); - this->active_tasks->destroy_offset(this->active_tasks, - offsetof(task_t, destroy)); - this->active_tasks = linked_list_create(); - this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); - this->queued_tasks = linked_list_create(); -} - -/** - * move a task of a specific type from the queue to the active list - */ -static bool activate_task(private_task_manager_t *this, task_type_t type) -{ - enumerator_t *enumerator; - task_t *task; - bool found = FALSE; - - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); - while (enumerator->enumerate(enumerator, (void**)&task)) - { - if (task->get_type(task) == type) - { - DBG2(DBG_IKE, " activating %N task", task_type_names, type); - this->queued_tasks->remove_at(this->queued_tasks, enumerator); - this->active_tasks->insert_last(this->active_tasks, task); - found = TRUE; - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -METHOD(task_manager_t, retransmit, status_t, - private_task_manager_t *this, u_int32_t message_id) -{ - if (message_id == this->initiating.mid) - { - u_int32_t timeout; - job_t *job; - enumerator_t *enumerator; - packet_t *packet; - task_t *task; - ike_mobike_t *mobike = NULL; - - /* check if we are retransmitting a MOBIKE routability check */ - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) - { - if (task->get_type(task) == IKE_MOBIKE) - { - mobike = (ike_mobike_t*)task; - if (!mobike->is_probing(mobike)) - { - mobike = NULL; - } - break; - } - } - enumerator->destroy(enumerator); - - if (mobike == NULL) - { - if (this->initiating.retransmitted <= this->retransmit_tries) - { - timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 * - pow(this->retransmit_base, this->initiating.retransmitted)); - } - else - { - DBG1(DBG_IKE, "giving up after %d retransmits", - this->initiating.retransmitted - 1); - if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) - { - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - return DESTROY_ME; - } - - if (this->initiating.retransmitted) - { - DBG1(DBG_IKE, "retransmit %d of request with message ID %d", - this->initiating.retransmitted, message_id); - } - packet = this->initiating.packet->clone(this->initiating.packet); - charon->sender->send(charon->sender, packet); - } - else - { /* for routeability checks, we use a more aggressive behavior */ - if (this->initiating.retransmitted <= ROUTEABILITY_CHECK_TRIES) - { - timeout = ROUTEABILITY_CHECK_INTERVAL; - } - else - { - DBG1(DBG_IKE, "giving up after %d path probings", - this->initiating.retransmitted - 1); - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - return DESTROY_ME; - } - - if (this->initiating.retransmitted) - { - DBG1(DBG_IKE, "path probing attempt %d", - this->initiating.retransmitted); - } - mobike->transmit(mobike, this->initiating.packet); - } - - this->initiating.retransmitted++; - job = (job_t*)retransmit_job_create(this->initiating.mid, - this->ike_sa->get_id(this->ike_sa)); - lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); - } - return SUCCESS; -} - -METHOD(task_manager_t, initiate, status_t, - private_task_manager_t *this) +task_manager_t *task_manager_create(ike_sa_t *ike_sa) { - enumerator_t *enumerator; - task_t *task; - message_t *message; - host_t *me, *other; - status_t status; - exchange_type_t exchange = 0; - - if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) - { - DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", - exchange_type_names, this->initiating.type); - /* do not initiate if we already have a message in the air */ - return SUCCESS; - } - - if (this->active_tasks->get_count(this->active_tasks) == 0) - { - DBG2(DBG_IKE, "activating new tasks"); - switch (this->ike_sa->get_state(this->ike_sa)) - { - case IKE_CREATED: - activate_task(this, IKE_VENDOR); - if (activate_task(this, IKE_INIT)) - { - this->initiating.mid = 0; - exchange = IKE_SA_INIT; - activate_task(this, IKE_NATD); - activate_task(this, IKE_CERT_PRE); -#ifdef ME - /* this task has to be activated before the IKE_AUTHENTICATE - * task, because that task pregenerates the packet after - * which no payloads can be added to the message anymore. - */ - activate_task(this, IKE_ME); -#endif /* ME */ - activate_task(this, IKE_AUTHENTICATE); - activate_task(this, IKE_CERT_POST); - activate_task(this, IKE_CONFIG); - activate_task(this, CHILD_CREATE); - activate_task(this, IKE_AUTH_LIFETIME); - activate_task(this, IKE_MOBIKE); - } - break; - case IKE_ESTABLISHED: - if (activate_task(this, CHILD_CREATE)) - { - exchange = CREATE_CHILD_SA; - break; - } - if (activate_task(this, CHILD_DELETE)) - { - exchange = INFORMATIONAL; - break; - } - if (activate_task(this, CHILD_REKEY)) - { - exchange = CREATE_CHILD_SA; - break; - } - if (activate_task(this, IKE_DELETE)) - { - exchange = INFORMATIONAL; - break; - } - if (activate_task(this, IKE_REKEY)) - { - exchange = CREATE_CHILD_SA; - break; - } - if (activate_task(this, IKE_REAUTH)) - { - exchange = INFORMATIONAL; - break; - } - if (activate_task(this, IKE_MOBIKE)) - { - exchange = INFORMATIONAL; - break; - } - if (activate_task(this, IKE_DPD)) - { - exchange = INFORMATIONAL; - break; - } - if (activate_task(this, IKE_AUTH_LIFETIME)) - { - exchange = INFORMATIONAL; - break; - } -#ifdef ME - if (activate_task(this, IKE_ME)) - { - exchange = ME_CONNECT; - break; - } -#endif /* ME */ - case IKE_REKEYING: - if (activate_task(this, IKE_DELETE)) - { - exchange = INFORMATIONAL; - break; - } - case IKE_DELETING: - default: - break; - } - } - else + switch (ike_sa->get_version(ike_sa)) { - DBG2(DBG_IKE, "reinitiating already active tasks"); - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void**)&task)) - { - DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); - switch (task->get_type(task)) - { - case IKE_INIT: - exchange = IKE_SA_INIT; - break; - case IKE_AUTHENTICATE: - exchange = IKE_AUTH; - break; - case CHILD_CREATE: - case CHILD_REKEY: - case IKE_REKEY: - exchange = CREATE_CHILD_SA; - break; - case IKE_MOBIKE: - exchange = INFORMATIONAL; - break; - default: - continue; - } + case IKEV1: +#ifdef USE_IKEV1 + return &task_manager_v1_create(ike_sa)->task_manager; +#endif break; - } - enumerator->destroy(enumerator); - } - - if (exchange == 0) - { - DBG2(DBG_IKE, "nothing to initiate"); - /* nothing to do yet... */ - return SUCCESS; - } - - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - - message = message_create(); - message->set_message_id(message, this->initiating.mid); - message->set_source(message, me->clone(me)); - message->set_destination(message, other->clone(other)); - message->set_exchange_type(message, exchange); - this->initiating.type = exchange; - this->initiating.retransmitted = 0; - - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) - { - switch (task->build(task, message)) - { - case SUCCESS: - /* task completed, remove it */ - this->active_tasks->remove_at(this->active_tasks, enumerator); - task->destroy(task); - break; - case NEED_MORE: - /* processed, but task needs another exchange */ - break; - case FAILED: - default: - if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) - { - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - /* FALL */ - case DESTROY_ME: - /* critical failure, destroy IKE_SA */ - enumerator->destroy(enumerator); - message->destroy(message); - flush(this); - return DESTROY_ME; - } - } - enumerator->destroy(enumerator); - - /* update exchange type if a task changed it */ - this->initiating.type = message->get_exchange_type(message); - - status = this->ike_sa->generate_message(this->ike_sa, message, - &this->initiating.packet); - if (status != SUCCESS) - { - /* message generation failed. There is nothing more to do than to - * close the SA */ - message->destroy(message); - flush(this); - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - return DESTROY_ME; - } - message->destroy(message); - - return retransmit(this, this->initiating.mid); -} - -/** - * handle an incoming response message - */ -static status_t process_response(private_task_manager_t *this, - message_t *message) -{ - enumerator_t *enumerator; - task_t *task; - - if (message->get_exchange_type(message) != this->initiating.type) - { - DBG1(DBG_IKE, "received %N response, but expected %N", - exchange_type_names, message->get_exchange_type(message), - exchange_type_names, this->initiating.type); - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - return DESTROY_ME; - } - - /* catch if we get resetted while processing */ - this->reset = FALSE; - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) - { - switch (task->process(task, message)) - { - case SUCCESS: - /* task completed, remove it */ - this->active_tasks->remove_at(this->active_tasks, enumerator); - task->destroy(task); - break; - case NEED_MORE: - /* processed, but task needs another exchange */ - break; - case FAILED: - default: - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - /* FALL */ - case DESTROY_ME: - /* critical failure, destroy IKE_SA */ - this->active_tasks->remove_at(this->active_tasks, enumerator); - enumerator->destroy(enumerator); - task->destroy(task); - return DESTROY_ME; - } - if (this->reset) - { /* start all over again if we were reset */ - this->reset = FALSE; - enumerator->destroy(enumerator); - return initiate(this); - } - } - enumerator->destroy(enumerator); - - this->initiating.mid++; - this->initiating.type = EXCHANGE_TYPE_UNDEFINED; - this->initiating.packet->destroy(this->initiating.packet); - this->initiating.packet = NULL; - - return initiate(this); -} - -/** - * handle exchange collisions - */ -static bool handle_collisions(private_task_manager_t *this, task_t *task) -{ - enumerator_t *enumerator; - task_t *active; - task_type_t type; - - type = task->get_type(task); - - /* do we have to check */ - if (type == IKE_REKEY || type == CHILD_REKEY || - type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) - { - /* find an exchange collision, and notify these tasks */ - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void**)&active)) - { - switch (active->get_type(active)) - { - case IKE_REKEY: - if (type == IKE_REKEY || type == IKE_DELETE || - type == IKE_REAUTH) - { - ike_rekey_t *rekey = (ike_rekey_t*)active; - rekey->collide(rekey, task); - break; - } - continue; - case CHILD_REKEY: - if (type == CHILD_REKEY || type == CHILD_DELETE) - { - child_rekey_t *rekey = (child_rekey_t*)active; - rekey->collide(rekey, task); - break; - } - continue; - default: - continue; - } - enumerator->destroy(enumerator); - return TRUE; - } - enumerator->destroy(enumerator); - } - return FALSE; -} - -/** - * build a response depending on the "passive" task list - */ -static status_t build_response(private_task_manager_t *this, message_t *request) -{ - enumerator_t *enumerator; - task_t *task; - message_t *message; - host_t *me, *other; - bool delete = FALSE, hook = FALSE; - status_t status; - - me = request->get_destination(request); - other = request->get_source(request); - - message = message_create(); - message->set_exchange_type(message, request->get_exchange_type(request)); - /* send response along the path the request came in */ - message->set_source(message, me->clone(me)); - message->set_destination(message, other->clone(other)); - message->set_message_id(message, this->responding.mid); - message->set_request(message, FALSE); - - enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) - { - switch (task->build(task, message)) - { - case SUCCESS: - /* task completed, remove it */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); - if (!handle_collisions(this, task)) - { - task->destroy(task); - } - break; - case NEED_MORE: - /* processed, but task needs another exchange */ - if (handle_collisions(this, task)) - { - this->passive_tasks->remove_at(this->passive_tasks, - enumerator); - } - break; - case FAILED: - default: - hook = TRUE; - /* FALL */ - case DESTROY_ME: - /* destroy IKE_SA, but SEND response first */ - delete = TRUE; - break; - } - if (delete) - { + case IKEV2: +#ifdef USE_IKEV2 + return &task_manager_v2_create(ike_sa)->task_manager; +#endif break; - } - } - enumerator->destroy(enumerator); - - /* remove resonder SPI if IKE_SA_INIT failed */ - if (delete && request->get_exchange_type(request) == IKE_SA_INIT) - { - ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); - id->set_responder_spi(id, 0); - } - - /* message complete, send it */ - DESTROY_IF(this->responding.packet); - this->responding.packet = NULL; - status = this->ike_sa->generate_message(this->ike_sa, message, - &this->responding.packet); - message->destroy(message); - if (status != SUCCESS) - { - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - return DESTROY_ME; - } - - charon->sender->send(charon->sender, - this->responding.packet->clone(this->responding.packet)); - if (delete) - { - if (hook) - { - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - return DESTROY_ME; - } - return SUCCESS; -} - -/** - * handle an incoming request message - */ -static status_t process_request(private_task_manager_t *this, - message_t *message) -{ - enumerator_t *enumerator; - task_t *task = NULL; - payload_t *payload; - notify_payload_t *notify; - delete_payload_t *delete; - - if (this->passive_tasks->get_count(this->passive_tasks) == 0) - { /* create tasks depending on request type, if not already some queued */ - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: - { - task = (task_t*)ike_vendor_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_natd_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); -#ifdef ME - task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); -#endif /* ME */ - task = (task_t*)ike_auth_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_config_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE, - NULL, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_mobike_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } - case CREATE_CHILD_SA: - { /* FIXME: we should prevent this on mediation connections */ - bool notify_found = FALSE, ts_found = FALSE; - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case NOTIFY: - { /* if we find a rekey notify, its CHILD_SA rekeying */ - notify = (notify_payload_t*)payload; - if (notify->get_notify_type(notify) == REKEY_SA && - (notify->get_protocol_id(notify) == PROTO_AH || - notify->get_protocol_id(notify) == PROTO_ESP)) - { - notify_found = TRUE; - } - break; - } - case TRAFFIC_SELECTOR_INITIATOR: - case TRAFFIC_SELECTOR_RESPONDER: - { /* if we don't find a TS, its IKE rekeying */ - ts_found = TRUE; - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); - - if (ts_found) - { - if (notify_found) - { - task = (task_t*)child_rekey_create(this->ike_sa, - PROTO_NONE, 0); - } - else - { - task = (task_t*)child_create_create(this->ike_sa, NULL, - FALSE, NULL, NULL); - } - } - else - { - task = (task_t*)ike_rekey_create(this->ike_sa, FALSE); - } - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } - case INFORMATIONAL: - { - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case NOTIFY: - { - notify = (notify_payload_t*)payload; - switch (notify->get_notify_type(notify)) - { - case ADDITIONAL_IP4_ADDRESS: - case ADDITIONAL_IP6_ADDRESS: - case NO_ADDITIONAL_ADDRESSES: - case UPDATE_SA_ADDRESSES: - case NO_NATS_ALLOWED: - case UNACCEPTABLE_ADDRESSES: - case UNEXPECTED_NAT_DETECTED: - case COOKIE2: - case NAT_DETECTION_SOURCE_IP: - case NAT_DETECTION_DESTINATION_IP: - task = (task_t*)ike_mobike_create( - this->ike_sa, FALSE); - break; - case AUTH_LIFETIME: - task = (task_t*)ike_auth_lifetime_create( - this->ike_sa, FALSE); - break; - default: - break; - } - break; - } - case DELETE: - { - delete = (delete_payload_t*)payload; - if (delete->get_protocol_id(delete) == PROTO_IKE) - { - task = (task_t*)ike_delete_create(this->ike_sa, - FALSE); - } - else - { - task = (task_t*)child_delete_create(this->ike_sa, - PROTO_NONE, 0); - } - break; - } - default: - break; - } - if (task) - { - break; - } - } - enumerator->destroy(enumerator); - - if (task == NULL) - { - task = (task_t*)ike_dpd_create(FALSE); - } - this->passive_tasks->insert_last(this->passive_tasks, task); - break; - } -#ifdef ME - case ME_CONNECT: - { - task = (task_t*)ike_me_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); - } -#endif /* ME */ - default: - break; - } - } - - /* let the tasks process the message */ - enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); - while (enumerator->enumerate(enumerator, (void*)&task)) - { - switch (task->process(task, message)) - { - case SUCCESS: - /* task completed, remove it */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); - task->destroy(task); - break; - case NEED_MORE: - /* processed, but task needs at least another call to build() */ - break; - case FAILED: - default: - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - /* FALL */ - case DESTROY_ME: - /* critical failure, destroy IKE_SA */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); - enumerator->destroy(enumerator); - task->destroy(task); - return DESTROY_ME; - } - } - enumerator->destroy(enumerator); - - return build_response(this, message); -} - -METHOD(task_manager_t, process_message, status_t, - private_task_manager_t *this, message_t *msg) -{ - host_t *me, *other; - u_int32_t mid; - - mid = msg->get_message_id(msg); - me = msg->get_destination(msg); - other = msg->get_source(msg); - - if (msg->get_request(msg)) - { - if (mid == this->responding.mid) - { - if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || - this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || - msg->get_exchange_type(msg) != IKE_SA_INIT) - { /* only do host updates based on verified messages */ - if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) - { /* with MOBIKE, we do no implicit updates */ - this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); - } - } - charon->bus->message(charon->bus, msg, TRUE); - if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) - { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ - return SUCCESS; - } - if (process_request(this, msg) != SUCCESS) - { - flush(this); - return DESTROY_ME; - } - this->responding.mid++; - } - else if ((mid == this->responding.mid - 1) && this->responding.packet) - { - packet_t *clone; - host_t *host; - - DBG1(DBG_IKE, "received retransmit of request with ID %d, " - "retransmitting response", mid); - clone = this->responding.packet->clone(this->responding.packet); - host = msg->get_destination(msg); - clone->set_source(clone, host->clone(host)); - host = msg->get_source(msg); - clone->set_destination(clone, host->clone(host)); - charon->sender->send(charon->sender, clone); - } - else - { - DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", - mid, this->responding.mid); - } - } - else - { - if (mid == this->initiating.mid) - { - if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED || - this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING || - msg->get_exchange_type(msg) != IKE_SA_INIT) - { /* only do host updates based on verified messages */ - if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) - { /* with MOBIKE, we do no implicit updates */ - this->ike_sa->update_hosts(this->ike_sa, me, other, FALSE); - } - } - charon->bus->message(charon->bus, msg, TRUE); - if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) - { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ - return SUCCESS; - } - if (process_response(this, msg) != SUCCESS) - { - flush(this); - return DESTROY_ME; - } - } - else - { - DBG1(DBG_IKE, "received message ID %d, expected %d. Ignored", - mid, this->initiating.mid); - return SUCCESS; - } - } - return SUCCESS; -} - -METHOD(task_manager_t, queue_task, void, - private_task_manager_t *this, task_t *task) -{ - if (task->get_type(task) == IKE_MOBIKE) - { /* there is no need to queue more than one mobike task */ - enumerator_t *enumerator; - task_t *current; - - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); - while (enumerator->enumerate(enumerator, (void**)¤t)) - { - if (current->get_type(current) == IKE_MOBIKE) - { - enumerator->destroy(enumerator); - task->destroy(task); - return; - } - } - enumerator->destroy(enumerator); - } - DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); - this->queued_tasks->insert_last(this->queued_tasks, task); -} - -METHOD(task_manager_t, adopt_tasks, void, - private_task_manager_t *this, task_manager_t *other_public) -{ - private_task_manager_t *other = (private_task_manager_t*)other_public; - task_t *task; - - /* move queued tasks from other to this */ - while (other->queued_tasks->remove_last(other->queued_tasks, - (void**)&task) == SUCCESS) - { - DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); - task->migrate(task, this->ike_sa); - this->queued_tasks->insert_first(this->queued_tasks, task); - } -} - -METHOD(task_manager_t, busy, bool, - private_task_manager_t *this) -{ - return (this->active_tasks->get_count(this->active_tasks) > 0); -} - -METHOD(task_manager_t, incr_mid, void, - private_task_manager_t *this, bool initiate) -{ - if (initiate) - { - this->initiating.mid++; - } - else - { - this->responding.mid++; - } -} - -METHOD(task_manager_t, reset, void, - private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) -{ - enumerator_t *enumerator; - task_t *task; - - /* reset message counters and retransmit packets */ - DESTROY_IF(this->responding.packet); - DESTROY_IF(this->initiating.packet); - this->responding.packet = NULL; - this->initiating.packet = NULL; - if (initiate != UINT_MAX) - { - this->initiating.mid = initiate; - } - if (respond != UINT_MAX) - { - this->responding.mid = respond; - } - this->initiating.type = EXCHANGE_TYPE_UNDEFINED; - - /* reset queued tasks */ - enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); - while (enumerator->enumerate(enumerator, &task)) - { - task->migrate(task, this->ike_sa); - } - enumerator->destroy(enumerator); - - /* reset active tasks */ - while (this->active_tasks->remove_last(this->active_tasks, - (void**)&task) == SUCCESS) - { - task->migrate(task, this->ike_sa); - this->queued_tasks->insert_first(this->queued_tasks, task); - } - - this->reset = TRUE; -} - -METHOD(task_manager_t, create_task_enumerator, enumerator_t*, - private_task_manager_t *this, task_queue_t queue) -{ - switch (queue) - { - case TASK_QUEUE_ACTIVE: - return this->active_tasks->create_enumerator(this->active_tasks); - case TASK_QUEUE_PASSIVE: - return this->passive_tasks->create_enumerator(this->passive_tasks); - case TASK_QUEUE_QUEUED: - return this->queued_tasks->create_enumerator(this->queued_tasks); default: - return enumerator_create_empty(); + break; } -} - -METHOD(task_manager_t, destroy, void, - private_task_manager_t *this) -{ - flush(this); - - this->active_tasks->destroy(this->active_tasks); - this->queued_tasks->destroy(this->queued_tasks); - this->passive_tasks->destroy(this->passive_tasks); - - DESTROY_IF(this->responding.packet); - DESTROY_IF(this->initiating.packet); - free(this); -} - -/* - * see header file - */ -task_manager_t *task_manager_create(ike_sa_t *ike_sa) -{ - private_task_manager_t *this; - - INIT(this, - .public = { - .process_message = _process_message, - .queue_task = _queue_task, - .initiate = _initiate, - .retransmit = _retransmit, - .incr_mid = _incr_mid, - .reset = _reset, - .adopt_tasks = _adopt_tasks, - .busy = _busy, - .create_task_enumerator = _create_task_enumerator, - .destroy = _destroy, - }, - .ike_sa = ike_sa, - .initiating.type = EXCHANGE_TYPE_UNDEFINED, - .queued_tasks = linked_list_create(), - .active_tasks = linked_list_create(), - .passive_tasks = linked_list_create(), - .retransmit_tries = lib->settings->get_int(lib->settings, - "charon.retransmit_tries", RETRANSMIT_TRIES), - .retransmit_timeout = lib->settings->get_double(lib->settings, - "charon.retransmit_timeout", RETRANSMIT_TIMEOUT), - .retransmit_base = lib->settings->get_double(lib->settings, - "charon.retransmit_base", RETRANSMIT_BASE), - ); - - return &this->public; + return NULL; } diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 5bc6c80c4..c649cf78e 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -29,7 +29,7 @@ typedef enum task_queue_t task_queue_t; #include #include #include -#include +#include /** * First retransmit timeout in seconds. @@ -124,6 +124,69 @@ struct task_manager_t { */ void (*queue_task) (task_manager_t *this, task_t *task); + /** + * Queue IKE_SA establishing tasks. + */ + void (*queue_ike)(task_manager_t *this); + + /** + * Queue IKE_SA rekey tasks. + */ + void (*queue_ike_rekey)(task_manager_t *this); + + /** + * Queue IKE_SA reauth tasks. + */ + void (*queue_ike_reauth)(task_manager_t *this); + + /** + * Queue MOBIKE task + * + * @param roam TRUE to switch to new address + * @param address TRUE to include address list update + */ + void (*queue_mobike)(task_manager_t *this, bool roam, bool address); + + /** + * Queue IKE_SA delete tasks. + */ + void (*queue_ike_delete)(task_manager_t *this); + + /** + * Queue CHILD_SA establishing tasks. + * + * @param cfg CHILD_SA config to establish + * @param reqid reqid to use for CHILD_SA + * @param tsi initiator traffic selector, if packet-triggered + * @param tsr responder traffic selector, if packet-triggered + */ + void (*queue_child)(task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr); + + /** + * Queue CHILD_SA rekeying tasks. + * + * @param protocol CHILD_SA protocol, AH|ESP + * @param spi CHILD_SA SPI to rekey + */ + void (*queue_child_rekey)(task_manager_t *this, protocol_id_t protocol, + u_int32_t spi); + + /** + * Queue CHILD_SA delete tasks. + * + * @param protocol CHILD_SA protocol, AH|ESP + * @param spi CHILD_SA SPI to rekey + * @param expired TRUE if SA already expired + */ + void (*queue_child_delete)(task_manager_t *this, protocol_id_t protocol, + u_int32_t spi, bool expired); + + /** + * Queue liveness checking tasks. + */ + void (*queue_dpd)(task_manager_t *this); + /** * Retransmit a request if it hasn't been acknowledged yet. * @@ -166,9 +229,11 @@ struct task_manager_t { * resets the message IDs and resets all active tasks using the migrate() * method. * Use a value of UINT_MAX to keep the current message ID. + * For IKEv1, the arguments do not set the message ID, but the DPD sequence + * number counters. * - * @param initiate message ID to initiate exchanges (send) - * @param respond message ID to respond to exchanges (expect) + * @param initiate message ID / DPD seq to initiate exchanges (send) + * @param respond message ID / DPD seq to respond to exchanges (expect) */ void (*reset) (task_manager_t *this, u_int32_t initiate, u_int32_t respond); @@ -188,6 +253,13 @@ struct task_manager_t { enumerator_t* (*create_task_enumerator)(task_manager_t *this, task_queue_t queue); + /** + * Flush a queue, cancelling all tasks. + * + * @param queue queue to flush + */ + void (*flush_queue)(task_manager_t *this, task_queue_t queue); + /** * Destroy the task_manager_t. */ @@ -195,9 +267,10 @@ struct task_manager_t { }; /** - * Create an instance of the task manager. + * Create a task manager instance for the correct IKE version. * - * @param ike_sa IKE_SA to manage. + * @param ike_sa IKE_SA to create a task manager for + * @return task manager implementation for IKE version */ task_manager_t *task_manager_create(ike_sa_t *ike_sa); diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c deleted file mode 100644 index 67c29d31f..000000000 --- a/src/libcharon/sa/tasks/child_create.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "child_create.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -typedef struct private_child_create_t private_child_create_t; - -/** - * Private members of a child_create_t task. - */ -struct private_child_create_t { - - /** - * Public methods and task_t interface. - */ - child_create_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * nonce chosen by us - */ - chunk_t my_nonce; - - /** - * nonce chosen by peer - */ - chunk_t other_nonce; - - /** - * config to create the CHILD_SA from - */ - child_cfg_t *config; - - /** - * list of proposal candidates - */ - linked_list_t *proposals; - - /** - * selected proposal to use for CHILD_SA - */ - proposal_t *proposal; - - /** - * traffic selectors for initiators side - */ - linked_list_t *tsi; - - /** - * traffic selectors for responders side - */ - linked_list_t *tsr; - - /** - * source of triggering packet - */ - traffic_selector_t *packet_tsi; - - /** - * destination of triggering packet - */ - traffic_selector_t *packet_tsr; - - /** - * optional diffie hellman exchange - */ - diffie_hellman_t *dh; - - /** - * group used for DH exchange - */ - diffie_hellman_group_t dh_group; - - /** - * IKE_SAs keymat - */ - keymat_t *keymat; - - /** - * mode the new CHILD_SA uses (transport/tunnel/beet) - */ - ipsec_mode_t mode; - - /** - * peer accepts TFC padding for this SA - */ - bool tfcv3; - - /** - * IPComp transform to use - */ - ipcomp_transform_t ipcomp; - - /** - * IPComp transform proposed or accepted by the other peer - */ - ipcomp_transform_t ipcomp_received; - - /** - * Own allocated SPI - */ - u_int32_t my_spi; - - /** - * SPI received in proposal - */ - u_int32_t other_spi; - - /** - * Own allocated Compression Parameter Index (CPI) - */ - u_int16_t my_cpi; - - /** - * Other Compression Parameter Index (CPI), received via IPCOMP_SUPPORTED - */ - u_int16_t other_cpi; - - /** - * reqid to use if we are rekeying - */ - u_int32_t reqid; - - /** - * CHILD_SA which gets established - */ - child_sa_t *child_sa; - - /** - * successfully established the CHILD? - */ - bool established; - - /** - * whether the CHILD_SA rekeys an existing one - */ - bool rekey; -}; - -/** - * get the nonce from a message - */ -static status_t get_nonce(message_t *message, chunk_t *nonce) -{ - nonce_payload_t *payload; - - payload = (nonce_payload_t*)message->get_payload(message, NONCE); - if (payload == NULL) - { - return FAILED; - } - *nonce = payload->get_nonce(payload); - return NEED_MORE; -} - -/** - * generate a new nonce to include in a CREATE_CHILD_SA message - */ -static status_t generate_nonce(chunk_t *nonce) -{ - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_IKE, "error generating nonce value, no RNG found"); - return FAILED; - } - rng->allocate_bytes(rng, NONCE_SIZE, nonce); - rng->destroy(rng); - return SUCCESS; -} - -/** - * Check a list of traffic selectors if any selector belongs to host - */ -static bool ts_list_is_host(linked_list_t *list, host_t *host) -{ - traffic_selector_t *ts; - bool is_host = TRUE; - enumerator_t *enumerator = list->create_enumerator(list); - - while (is_host && enumerator->enumerate(enumerator, (void**)&ts)) - { - is_host = is_host && ts->is_host(ts, host); - } - enumerator->destroy(enumerator); - return is_host; -} - -/** - * Allocate SPIs and update proposals - */ -static bool allocate_spi(private_child_create_t *this) -{ - enumerator_t *enumerator; - proposal_t *proposal; - - /* TODO: allocate additional SPI for AH if we have such proposals */ - this->my_spi = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); - if (this->my_spi) - { - if (this->initiator) - { - enumerator = this->proposals->create_enumerator(this->proposals); - while (enumerator->enumerate(enumerator, &proposal)) - { - proposal->set_spi(proposal, this->my_spi); - } - enumerator->destroy(enumerator); - } - else - { - this->proposal->set_spi(this->proposal, this->my_spi); - } - return TRUE; - } - return FALSE; -} - -/** - * Schedule inactivity timeout for CHILD_SA with reqid, if enabled - */ -static void schedule_inactivity_timeout(private_child_create_t *this) -{ - u_int32_t timeout; - bool close_ike; - - timeout = this->config->get_inactivity(this->config); - if (timeout) - { - close_ike = lib->settings->get_bool(lib->settings, - "charon.inactivity_close_ike", FALSE); - lib->scheduler->schedule_job(lib->scheduler, (job_t*) - inactivity_job_create(this->child_sa->get_reqid(this->child_sa), - timeout, close_ike), timeout); - } -} - -/** - * Install a CHILD_SA for usage, return value: - * - FAILED: no acceptable proposal - * - INVALID_ARG: diffie hellman group inacceptable - * - NOT_FOUND: TS inacceptable - */ -static status_t select_and_install(private_child_create_t *this, - bool no_dh, bool ike_auth) -{ - status_t status, status_i, status_o; - chunk_t nonce_i, nonce_r; - chunk_t encr_i = chunk_empty, encr_r = chunk_empty; - chunk_t integ_i = chunk_empty, integ_r = chunk_empty; - linked_list_t *my_ts, *other_ts; - host_t *me, *other, *other_vip, *my_vip; - bool private; - - if (this->proposals == NULL) - { - DBG1(DBG_IKE, "SA payload missing in message"); - return FAILED; - } - if (this->tsi == NULL || this->tsr == NULL) - { - DBG1(DBG_IKE, "TS payloads missing in message"); - return NOT_FOUND; - } - - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - - private = this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN); - this->proposal = this->config->select_proposal(this->config, - this->proposals, no_dh, private); - if (this->proposal == NULL) - { - DBG1(DBG_IKE, "no acceptable proposal found"); - return FAILED; - } - this->other_spi = this->proposal->get_spi(this->proposal); - - if (!this->initiator && !allocate_spi(this)) - { /* responder has no SPI allocated yet */ - DBG1(DBG_IKE, "allocating SPI failed"); - return FAILED; - } - this->child_sa->set_proposal(this->child_sa, this->proposal); - - if (!this->proposal->has_dh_group(this->proposal, this->dh_group)) - { - u_int16_t group; - - if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, - &group, NULL)) - { - DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", - diffie_hellman_group_names, this->dh_group, - diffie_hellman_group_names, group); - this->dh_group = group; - return INVALID_ARG; - } - /* the selected proposal does not use a DH group */ - DBG1(DBG_IKE, "ignoring KE exchange, agreed on a non-PFS proposal"); - DESTROY_IF(this->dh); - this->dh = NULL; - this->dh_group = MODP_NONE; - } - - if (my_vip == NULL) - { - my_vip = me; - } - if (other_vip == NULL) - { - other_vip = other; - } - - if (this->initiator) - { - nonce_i = this->my_nonce; - nonce_r = this->other_nonce; - my_ts = this->tsi; - other_ts = this->tsr; - } - else - { - nonce_r = this->my_nonce; - nonce_i = this->other_nonce; - my_ts = this->tsr; - other_ts = this->tsi; - } - my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts, - my_vip); - other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts, - other_vip); - - if (this->initiator) - { - if (ike_auth) - { - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_INITIATOR_POST_NOAUTH, my_ts, other_ts); - } - else - { - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_INITIATOR_POST_AUTH, my_ts, other_ts); - } - } - else - { - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_RESPONDER, my_ts, other_ts); - } - - if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) - { - my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); - other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); - DBG1(DBG_IKE, "no acceptable traffic selectors found"); - return NOT_FOUND; - } - - this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); - this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); - if (this->initiator) - { - this->tsi = my_ts; - this->tsr = other_ts; - } - else - { - this->tsr = my_ts; - this->tsi = other_ts; - } - - if (!this->initiator) - { - /* check if requested mode is acceptable, downgrade if required */ - switch (this->mode) - { - case MODE_TRANSPORT: - if (!this->config->use_proxy_mode(this->config) && - (!ts_list_is_host(this->tsi, other) || - !ts_list_is_host(this->tsr, me)) - ) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using transport mode, not host-to-host"); - } - else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using transport mode, connection NATed"); - } - break; - case MODE_BEET: - if (!ts_list_is_host(this->tsi, NULL) || - !ts_list_is_host(this->tsr, NULL)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using BEET mode, not host-to-host"); - } - break; - default: - break; - } - } - - this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); - this->child_sa->set_ipcomp(this->child_sa, this->ipcomp); - this->child_sa->set_mode(this->child_sa, this->mode); - this->child_sa->set_protocol(this->child_sa, - this->proposal->get_protocol(this->proposal)); - - if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE) - { - this->my_cpi = this->other_cpi = 0; - this->ipcomp = IPCOMP_NONE; - } - status_i = status_o = FAILED; - if (this->keymat->derive_child_keys(this->keymat, this->proposal, - this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) - { - if (this->initiator) - { - status_i = this->child_sa->install(this->child_sa, - encr_r, integ_r, this->my_spi, this->my_cpi, - TRUE, this->tfcv3, my_ts, other_ts); - status_o = this->child_sa->install(this->child_sa, - encr_i, integ_i, this->other_spi, this->other_cpi, - FALSE, this->tfcv3, my_ts, other_ts); - } - else - { - status_i = this->child_sa->install(this->child_sa, - encr_i, integ_i, this->my_spi, this->my_cpi, - TRUE, this->tfcv3, my_ts, other_ts); - status_o = this->child_sa->install(this->child_sa, - encr_r, integ_r, this->other_spi, this->other_cpi, - FALSE, this->tfcv3, my_ts, other_ts); - } - } - chunk_clear(&integ_i); - chunk_clear(&integ_r); - chunk_clear(&encr_i); - chunk_clear(&encr_r); - - if (status_i != SUCCESS || status_o != SUCCESS) - { - DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel", - (status_i != SUCCESS) ? "inbound " : "", - (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", - (status_o != SUCCESS) ? "outbound " : ""); - return FAILED; - } - - status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts); - if (status != SUCCESS) - { - DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); - return NOT_FOUND; - } - - charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, - this->dh, nonce_i, nonce_r); - - /* add to IKE_SA, and remove from task */ - this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); - this->established = TRUE; - - if (!this->rekey) - { /* a rekeyed SA uses the same reqid, no need for a new job */ - schedule_inactivity_timeout(this); - } - return SUCCESS; -} - -/** - * build the payloads for the message - */ -static void build_payloads(private_child_create_t *this, message_t *message) -{ - sa_payload_t *sa_payload; - nonce_payload_t *nonce_payload; - ke_payload_t *ke_payload; - ts_payload_t *ts_payload; - - /* add SA payload */ - if (this->initiator) - { - sa_payload = sa_payload_create_from_proposal_list(this->proposals); - } - else - { - sa_payload = sa_payload_create_from_proposal(this->proposal); - } - message->add_payload(message, (payload_t*)sa_payload); - - /* add nonce payload if not in IKE_AUTH */ - if (message->get_exchange_type(message) == CREATE_CHILD_SA) - { - nonce_payload = nonce_payload_create(); - nonce_payload->set_nonce(nonce_payload, this->my_nonce); - message->add_payload(message, (payload_t*)nonce_payload); - } - - /* diffie hellman exchange, if PFS enabled */ - if (this->dh) - { - ke_payload = ke_payload_create_from_diffie_hellman(this->dh); - message->add_payload(message, (payload_t*)ke_payload); - } - - /* add TSi/TSr payloads */ - ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); - message->add_payload(message, (payload_t*)ts_payload); - ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr); - message->add_payload(message, (payload_t*)ts_payload); - - /* add a notify if we are not in tunnel mode */ - switch (this->mode) - { - case MODE_TRANSPORT: - message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty); - break; - case MODE_BEET: - message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty); - break; - default: - break; - } -} - -/** - * Adds an IPCOMP_SUPPORTED notify to the message, allocating a CPI - */ -static void add_ipcomp_notify(private_child_create_t *this, - message_t *message, u_int8_t ipcomp) -{ - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) - { - DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, " - "IPComp disabled"); - return; - } - - this->my_cpi = this->child_sa->alloc_cpi(this->child_sa); - if (this->my_cpi) - { - this->ipcomp = ipcomp; - message->add_notify(message, FALSE, IPCOMP_SUPPORTED, - chunk_cata("cc", chunk_from_thing(this->my_cpi), - chunk_from_thing(ipcomp))); - } - else - { - DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled"); - } -} - -/** - * handle a received notify payload - */ -static void handle_notify(private_child_create_t *this, notify_payload_t *notify) -{ - switch (notify->get_notify_type(notify)) - { - case USE_TRANSPORT_MODE: - this->mode = MODE_TRANSPORT; - break; - case USE_BEET_MODE: - if (this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN)) - { /* handle private use notify only if we know its meaning */ - this->mode = MODE_BEET; - } - else - { - DBG1(DBG_IKE, "received a notify strongSwan uses for BEET " - "mode, but peer implementation unknown, skipped"); - } - break; - case IPCOMP_SUPPORTED: - { - ipcomp_transform_t ipcomp; - u_int16_t cpi; - chunk_t data; - - data = notify->get_notification_data(notify); - cpi = *(u_int16_t*)data.ptr; - ipcomp = (ipcomp_transform_t)(*(data.ptr + 2)); - switch (ipcomp) - { - case IPCOMP_DEFLATE: - this->other_cpi = cpi; - this->ipcomp_received = ipcomp; - break; - case IPCOMP_LZS: - case IPCOMP_LZJH: - default: - DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a " - "transform ID we don't support %N", - ipcomp_transform_names, ipcomp); - break; - } - break; - } - case ESP_TFC_PADDING_NOT_SUPPORTED: - DBG1(DBG_IKE, "received %N, not using ESPv3 TFC padding", - notify_type_names, notify->get_notify_type(notify)); - this->tfcv3 = FALSE; - break; - default: - break; - } -} - -/** - * Read payloads from message - */ -static void process_payloads(private_child_create_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - sa_payload_t *sa_payload; - ke_payload_t *ke_payload; - ts_payload_t *ts_payload; - - /* defaults to TUNNEL mode */ - this->mode = MODE_TUNNEL; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case SECURITY_ASSOCIATION: - sa_payload = (sa_payload_t*)payload; - this->proposals = sa_payload->get_proposals(sa_payload); - break; - case KEY_EXCHANGE: - ke_payload = (ke_payload_t*)payload; - if (!this->initiator) - { - this->dh_group = ke_payload->get_dh_group_number(ke_payload); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); - } - if (this->dh) - { - this->dh->set_other_public_value(this->dh, - ke_payload->get_key_exchange_data(ke_payload)); - } - break; - case TRAFFIC_SELECTOR_INITIATOR: - ts_payload = (ts_payload_t*)payload; - this->tsi = ts_payload->get_traffic_selectors(ts_payload); - break; - case TRAFFIC_SELECTOR_RESPONDER: - ts_payload = (ts_payload_t*)payload; - this->tsr = ts_payload->get_traffic_selectors(ts_payload); - break; - case NOTIFY: - handle_notify(this, (notify_payload_t*)payload); - break; - default: - break; - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_child_create_t *this, message_t *message) -{ - host_t *me, *other, *vip; - peer_cfg_t *peer_cfg; - - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: - return get_nonce(message, &this->my_nonce); - case CREATE_CHILD_SA: - if (generate_nonce(&this->my_nonce) != SUCCESS) - { - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); - return SUCCESS; - } - if (this->dh_group == MODP_NONE) - { - this->dh_group = this->config->get_dh_group(this->config); - } - break; - case IKE_AUTH: - if (message->get_message_id(message) != 1) - { - /* send only in the first request, not in subsequent rounds */ - return NEED_MORE; - } - break; - default: - break; - } - - if (this->reqid) - { - DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}", - this->config->get_name(this->config), this->reqid); - } - else - { - DBG0(DBG_IKE, "establishing CHILD_SA %s", - this->config->get_name(this->config)); - } - - /* reuse virtual IP if we already have one */ - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - - /* check if we want a virtual IP, but don't have one */ - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = peer_cfg->get_virtual_ip(peer_cfg); - if (!this->reqid && vip) - { - /* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */ - vip = host_create_any(vip->get_family(vip)); - this->tsi = this->config->get_traffic_selectors(this->config, TRUE, - NULL, vip); - vip->destroy(vip); - } - else - { /* but narrow it for host2host / if we already have a vip */ - this->tsi = this->config->get_traffic_selectors(this->config, TRUE, - NULL, me); - } - this->tsr = this->config->get_traffic_selectors(this->config, FALSE, - NULL, other); - - if (this->packet_tsi) - { - this->tsi->insert_first(this->tsi, - this->packet_tsi->clone(this->packet_tsi)); - } - if (this->packet_tsr) - { - this->tsr->insert_first(this->tsr, - this->packet_tsr->clone(this->packet_tsr)); - } - this->proposals = this->config->get_proposals(this->config, - this->dh_group == MODP_NONE); - this->mode = this->config->get_mode(this->config); - if (this->mode == MODE_TRANSPORT && - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) - { - this->mode = MODE_TUNNEL; - DBG1(DBG_IKE, "not using transport mode, connection NATed"); - } - - this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - - if (!allocate_spi(this)) - { - DBG1(DBG_IKE, "unable to allocate SPIs from kernel"); - return FAILED; - } - - if (this->dh_group != MODP_NONE) - { - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); - } - - if (this->config->use_ipcomp(this->config)) - { - /* IPCOMP_DEFLATE is the only transform we support at the moment */ - add_ipcomp_notify(this, message, IPCOMP_DEFLATE); - } - - if (message->get_exchange_type(message) == IKE_AUTH) - { - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_INITIATOR_PRE_NOAUTH, this->tsi, this->tsr); - } - else - { - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_INITIATOR_PRE_AUTH, this->tsi, this->tsr); - } - - build_payloads(this, message); - - this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); - this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); - this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); - this->tsi = NULL; - this->tsr = NULL; - this->proposals = NULL; - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_child_create_t *this, message_t *message) -{ - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: - return get_nonce(message, &this->other_nonce); - case CREATE_CHILD_SA: - get_nonce(message, &this->other_nonce); - break; - case IKE_AUTH: - if (message->get_message_id(message) != 1) - { - /* only handle first AUTH payload, not additional rounds */ - return NEED_MORE; - } - default: - break; - } - - process_payloads(this, message); - - return NEED_MORE; -} - -/** - * handle CHILD_SA setup failure - */ -static void handle_child_sa_failure(private_child_create_t *this, - message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - lib->settings->get_bool(lib->settings, - "charon.close_ike_on_child_failure", FALSE)) - { - /* we delay the delete for 100ms, as the IKE_AUTH response must arrive - * first */ - DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure"); - lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) - delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), - 100); - } - else - { - DBG1(DBG_IKE, "failed to establish CHILD_SA, keeping IKE_SA"); - } -} - -METHOD(task_t, build_r, status_t, - private_child_create_t *this, message_t *message) -{ - peer_cfg_t *peer_cfg; - payload_t *payload; - enumerator_t *enumerator; - bool no_dh = TRUE, ike_auth = FALSE; - - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: - return get_nonce(message, &this->my_nonce); - case CREATE_CHILD_SA: - if (generate_nonce(&this->my_nonce) != SUCCESS) - { - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, - chunk_empty); - return SUCCESS; - } - no_dh = FALSE; - break; - case IKE_AUTH: - if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { /* wait until all authentication round completed */ - return NEED_MORE; - } - ike_auth = TRUE; - default: - break; - } - - if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) - { - DBG1(DBG_IKE, "unable to create CHILD_SA while rekeying IKE_SA"); - message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty); - return SUCCESS; - } - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg && this->tsi && this->tsr) - { - host_t *me, *other; - - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, - this->tsi, me, other); - } - - if (this->config == NULL) - { - DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable", - this->tsr, this->tsi); - message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); - handle_child_sa_failure(this, message); - return SUCCESS; - } - - /* check if ike_config_t included non-critical error notifies */ - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == NOTIFY) - { - notify_payload_t *notify = (notify_payload_t*)payload; - - switch (notify->get_notify_type(notify)) - { - case INTERNAL_ADDRESS_FAILURE: - case FAILED_CP_REQUIRED: - { - DBG1(DBG_IKE,"configuration payload negotiation " - "failed, no CHILD_SA built"); - enumerator->destroy(enumerator); - handle_child_sa_failure(this, message); - return SUCCESS; - } - default: - break; - } - } - } - enumerator->destroy(enumerator); - - this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)); - - if (this->ipcomp_received != IPCOMP_NONE) - { - if (this->config->use_ipcomp(this->config)) - { - add_ipcomp_notify(this, message, this->ipcomp_received); - } - else - { - DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring", - notify_type_names, IPCOMP_SUPPORTED); - } - } - - switch (select_and_install(this, no_dh, ike_auth)) - { - case SUCCESS: - break; - case NOT_FOUND: - message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); - handle_child_sa_failure(this, message); - return SUCCESS; - case INVALID_ARG: - { - u_int16_t group = htons(this->dh_group); - message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, - chunk_from_thing(group)); - handle_child_sa_failure(this, message); - return SUCCESS; - } - case FAILED: - default: - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); - handle_child_sa_failure(this, message); - return SUCCESS; - } - - build_payloads(this, message); - - DBG0(DBG_IKE, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); - - if (!this->rekey) - { /* invoke the child_up() hook if we are not rekeying */ - charon->bus->child_updown(charon->bus, this->child_sa, TRUE); - } - return SUCCESS; -} - -METHOD(task_t, process_i, status_t, - private_child_create_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - bool no_dh = TRUE, ike_auth = FALSE; - - switch (message->get_exchange_type(message)) - { - case IKE_SA_INIT: - return get_nonce(message, &this->other_nonce); - case CREATE_CHILD_SA: - get_nonce(message, &this->other_nonce); - no_dh = FALSE; - break; - case IKE_AUTH: - if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { /* wait until all authentication round completed */ - return NEED_MORE; - } - ike_auth = TRUE; - default: - break; - } - - /* check for erronous notifies */ - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == NOTIFY) - { - notify_payload_t *notify = (notify_payload_t*)payload; - notify_type_t type = notify->get_notify_type(notify); - - switch (type) - { - /* handle notify errors related to CHILD_SA only */ - case NO_PROPOSAL_CHOSEN: - case SINGLE_PAIR_REQUIRED: - case NO_ADDITIONAL_SAS: - case INTERNAL_ADDRESS_FAILURE: - case FAILED_CP_REQUIRED: - case TS_UNACCEPTABLE: - case INVALID_SELECTORS: - { - DBG1(DBG_IKE, "received %N notify, no CHILD_SA built", - notify_type_names, type); - enumerator->destroy(enumerator); - handle_child_sa_failure(this, message); - /* an error in CHILD_SA creation is not critical */ - return SUCCESS; - } - case INVALID_KE_PAYLOAD: - { - chunk_t data; - u_int16_t group = MODP_NONE; - - data = notify->get_notification_data(notify); - if (data.len == sizeof(group)) - { - memcpy(&group, data.ptr, data.len); - group = ntohs(group); - } - DBG1(DBG_IKE, "peer didn't accept DH group %N, " - "it requested %N", diffie_hellman_group_names, - this->dh_group, diffie_hellman_group_names, group); - this->dh_group = group; - this->public.task.migrate(&this->public.task, this->ike_sa); - enumerator->destroy(enumerator); - return NEED_MORE; - } - default: - { - if (message->get_exchange_type(message) == CREATE_CHILD_SA) - { /* handle notifies if not handled in IKE_AUTH */ - if (type <= 16383) - { - DBG1(DBG_IKE, "received %N notify error", - notify_type_names, type); - enumerator->destroy(enumerator); - return SUCCESS; - } - DBG2(DBG_IKE, "received %N notify", - notify_type_names, type); - } - break; - } - } - } - } - enumerator->destroy(enumerator); - - process_payloads(this, message); - - if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE) - { - DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting" - " one, no CHILD_SA built"); - handle_child_sa_failure(this, message); - return SUCCESS; - } - else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE) - { - DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, " - "IPComp is disabled"); - this->ipcomp = IPCOMP_NONE; - } - else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received) - { - DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, " - "no CHILD_SA built"); - handle_child_sa_failure(this, message); - return SUCCESS; - } - - if (select_and_install(this, no_dh, ike_auth) == SUCCESS) - { - DBG0(DBG_IKE, "CHILD_SA %s{%d} established " - "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", - this->child_sa->get_name(this->child_sa), - this->child_sa->get_reqid(this->child_sa), - ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), - ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), - this->child_sa->get_traffic_selectors(this->child_sa, TRUE), - this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); - - if (!this->rekey) - { /* invoke the child_up() hook if we are not rekeying */ - charon->bus->child_updown(charon->bus, this->child_sa, TRUE); - } - } - else - { - handle_child_sa_failure(this, message); - } - return SUCCESS; -} - -METHOD(child_create_t, use_reqid, void, - private_child_create_t *this, u_int32_t reqid) -{ - this->reqid = reqid; -} - -METHOD(child_create_t, get_child, child_sa_t*, - private_child_create_t *this) -{ - return this->child_sa; -} - -METHOD(child_create_t, get_lower_nonce, chunk_t, - private_child_create_t *this) -{ - if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, - min(this->my_nonce.len, this->other_nonce.len)) < 0) - { - return this->my_nonce; - } - else - { - return this->other_nonce; - } -} - -METHOD(task_t, get_type, task_type_t, - private_child_create_t *this) -{ - return CHILD_CREATE; -} - -METHOD(task_t, migrate, void, - private_child_create_t *this, ike_sa_t *ike_sa) -{ - chunk_free(&this->my_nonce); - chunk_free(&this->other_nonce); - if (this->tsr) - { - this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); - } - if (this->tsi) - { - this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); - } - DESTROY_IF(this->child_sa); - DESTROY_IF(this->proposal); - DESTROY_IF(this->dh); - if (this->proposals) - { - this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); - } - - this->ike_sa = ike_sa; - this->keymat = ike_sa->get_keymat(ike_sa); - this->proposal = NULL; - this->proposals = NULL; - this->tsi = NULL; - this->tsr = NULL; - this->dh = NULL; - this->child_sa = NULL; - this->mode = MODE_TUNNEL; - this->ipcomp = IPCOMP_NONE; - this->ipcomp_received = IPCOMP_NONE; - this->other_cpi = 0; - this->reqid = 0; - this->established = FALSE; -} - -METHOD(task_t, destroy, void, - private_child_create_t *this) -{ - chunk_free(&this->my_nonce); - chunk_free(&this->other_nonce); - if (this->tsr) - { - this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); - } - if (this->tsi) - { - this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); - } - if (!this->established) - { - DESTROY_IF(this->child_sa); - } - DESTROY_IF(this->packet_tsi); - DESTROY_IF(this->packet_tsr); - DESTROY_IF(this->proposal); - DESTROY_IF(this->dh); - if (this->proposals) - { - this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); - } - - DESTROY_IF(this->config); - free(this); -} - -/* - * Described in header. - */ -child_create_t *child_create_create(ike_sa_t *ike_sa, - child_cfg_t *config, bool rekey, - traffic_selector_t *tsi, traffic_selector_t *tsr) -{ - private_child_create_t *this; - - INIT(this, - .public = { - .get_child = _get_child, - .get_lower_nonce = _get_lower_nonce, - .use_reqid = _use_reqid, - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .config = config, - .packet_tsi = tsi ? tsi->clone(tsi) : NULL, - .packet_tsr = tsr ? tsr->clone(tsr) : NULL, - .dh_group = MODP_NONE, - .keymat = ike_sa->get_keymat(ike_sa), - .mode = MODE_TUNNEL, - .tfcv3 = TRUE, - .ipcomp = IPCOMP_NONE, - .ipcomp_received = IPCOMP_NONE, - .rekey = rekey, - ); - - if (config) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - this->initiator = TRUE; - config->get_ref(config); - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - this->initiator = FALSE; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/child_create.h b/src/libcharon/sa/tasks/child_create.h deleted file mode 100644 index 5dedeb8b1..000000000 --- a/src/libcharon/sa/tasks/child_create.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup child_create child_create - * @{ @ingroup tasks - */ - -#ifndef CHILD_CREATE_H_ -#define CHILD_CREATE_H_ - -typedef struct child_create_t child_create_t; - -#include -#include -#include -#include - -/** - * Task of type CHILD_CREATE, established a new CHILD_SA. - * - * This task may be included in the IKE_AUTH message or in a separate - * CREATE_CHILD_SA exchange. - */ -struct child_create_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Use a specific reqid for the CHILD_SA. - * - * When this task is used for rekeying, the same reqid is used - * for the new CHILD_SA. - * - * @param reqid reqid to use - */ - void (*use_reqid) (child_create_t *this, u_int32_t reqid); - - /** - * Get the lower of the two nonces, used for rekey collisions. - * - * @return lower nonce - */ - chunk_t (*get_lower_nonce) (child_create_t *this); - - /** - * Get the CHILD_SA established/establishing by this task. - * - * @return child_sa - */ - child_sa_t* (*get_child) (child_create_t *this); -}; - -/** - * Create a new child_create task. - * - * @param ike_sa IKE_SA this task works for - * @param config child_cfg if task initiator, NULL if responder - * @param rekey whether we do a rekey or not - * @param tsi source of triggering packet, or NULL - * @param tsr destination of triggering packet, or NULL - * @return child_create task to handle by the task_manager - */ -child_create_t *child_create_create(ike_sa_t *ike_sa, - child_cfg_t *config, bool rekey, - traffic_selector_t *tsi, traffic_selector_t *tsr); - -#endif /** CHILD_CREATE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c deleted file mode 100644 index dc4b30dd3..000000000 --- a/src/libcharon/sa/tasks/child_delete.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Copyright (C) 2006-2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "child_delete.h" - -#include -#include - - -typedef struct private_child_delete_t private_child_delete_t; - -/** - * Private members of a child_delete_t task. - */ -struct private_child_delete_t { - - /** - * Public methods and task_t interface. - */ - child_delete_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Protocol of CHILD_SA to delete - */ - protocol_id_t protocol; - - /** - * Inbound SPI of CHILD_SA to delete - */ - u_int32_t spi; - - /** - * whether to enforce delete action policy - */ - bool check_delete_action; - - /** - * is this delete exchange following a rekey? - */ - bool rekeyed; - - /** - * CHILD_SAs which get deleted - */ - linked_list_t *child_sas; -}; - -/** - * build the delete payloads from the listed child_sas - */ -static void build_payloads(private_child_delete_t *this, message_t *message) -{ - delete_payload_t *ah = NULL, *esp = NULL; - enumerator_t *enumerator; - child_sa_t *child_sa; - - enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - protocol_id_t protocol = child_sa->get_protocol(child_sa); - u_int32_t spi = child_sa->get_spi(child_sa, TRUE); - - switch (protocol) - { - case PROTO_ESP: - if (esp == NULL) - { - esp = delete_payload_create(PROTO_ESP); - message->add_payload(message, (payload_t*)esp); - } - esp->add_spi(esp, spi); - DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(spi)); - break; - case PROTO_AH: - if (ah == NULL) - { - ah = delete_payload_create(PROTO_AH); - message->add_payload(message, (payload_t*)ah); - } - ah->add_spi(ah, spi); - DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(spi)); - break; - default: - break; - } - child_sa->set_state(child_sa, CHILD_DELETING); - } - enumerator->destroy(enumerator); -} - -/** - * read in payloads and find the children to delete - */ -static void process_payloads(private_child_delete_t *this, message_t *message) -{ - enumerator_t *payloads, *spis; - payload_t *payload; - delete_payload_t *delete_payload; - u_int32_t spi; - protocol_id_t protocol; - child_sa_t *child_sa; - - payloads = message->create_payload_enumerator(message); - while (payloads->enumerate(payloads, &payload)) - { - if (payload->get_type(payload) == DELETE) - { - delete_payload = (delete_payload_t*)payload; - protocol = delete_payload->get_protocol_id(delete_payload); - if (protocol != PROTO_ESP && protocol != PROTO_AH) - { - continue; - } - spis = delete_payload->create_spi_enumerator(delete_payload); - while (spis->enumerate(spis, &spi)) - { - child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, - spi, FALSE); - if (child_sa == NULL) - { - DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x, " - "but no such SA", protocol_id_names, protocol, ntohl(spi)); - continue; - } - DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", - protocol_id_names, protocol, ntohl(spi)); - - switch (child_sa->get_state(child_sa)) - { - case CHILD_REKEYING: - this->rekeyed = TRUE; - /* we reply as usual, rekeying will fail */ - break; - case CHILD_DELETING: - /* we don't send back a delete if we initiated ourself */ - if (!this->initiator) - { - this->ike_sa->destroy_child_sa(this->ike_sa, - protocol, spi); - continue; - } - /* fall through */ - case CHILD_INSTALLED: - if (!this->initiator) - { /* reestablish installed children if required */ - this->check_delete_action = TRUE; - } - default: - break; - } - - this->child_sas->insert_last(this->child_sas, child_sa); - } - spis->destroy(spis); - } - } - payloads->destroy(payloads); -} - -/** - * destroy the children listed in this->child_sas, reestablish by policy - */ -static status_t destroy_and_reestablish(private_child_delete_t *this) -{ - enumerator_t *enumerator; - child_sa_t *child_sa; - child_cfg_t *child_cfg; - protocol_id_t protocol; - u_int32_t spi; - action_t action; - status_t status = SUCCESS; - - enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - /* signal child down event if we are not rekeying */ - if (!this->rekeyed) - { - charon->bus->child_updown(charon->bus, child_sa, FALSE); - } - spi = child_sa->get_spi(child_sa, TRUE); - protocol = child_sa->get_protocol(child_sa); - child_cfg = child_sa->get_config(child_sa); - child_cfg->get_ref(child_cfg); - action = child_sa->get_close_action(child_sa); - this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); - if (this->check_delete_action) - { /* enforce child_cfg policy if deleted passively */ - switch (action) - { - case ACTION_RESTART: - child_cfg->get_ref(child_cfg); - status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0, - NULL, NULL); - break; - case ACTION_ROUTE: - charon->traps->install(charon->traps, - this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg); - break; - default: - break; - } - } - child_cfg->destroy(child_cfg); - if (status != SUCCESS) - { - break; - } - } - enumerator->destroy(enumerator); - return status; -} - -/** - * send closing signals for all CHILD_SAs over the bus - */ -static void log_children(private_child_delete_t *this) -{ - enumerator_t *enumerator; - child_sa_t *child_sa; - u_int64_t bytes_in, bytes_out; - - enumerator = this->child_sas->create_enumerator(this->child_sas); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); - child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); - - DBG0(DBG_IKE, "closing CHILD_SA %s{%d} " - "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", - child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, - ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_child_delete_t *this, message_t *message) -{ - child_sa_t *child_sa; - - child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, - this->spi, TRUE); - if (!child_sa) - { /* check if it is an outbound sa */ - child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, - this->spi, FALSE); - if (!child_sa) - { /* child does not exist anymore */ - return SUCCESS; - } - /* we work only with the inbound SPI */ - this->spi = child_sa->get_spi(child_sa, TRUE); - } - this->child_sas->insert_last(this->child_sas, child_sa); - if (child_sa->get_state(child_sa) == CHILD_REKEYING) - { - this->rekeyed = TRUE; - } - log_children(this); - build_payloads(this, message); - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_child_delete_t *this, message_t *message) -{ - /* flush the list before adding new SAs */ - this->child_sas->destroy(this->child_sas); - this->child_sas = linked_list_create(); - - process_payloads(this, message); - DBG1(DBG_IKE, "CHILD_SA closed"); - return destroy_and_reestablish(this); -} - -METHOD(task_t, process_r, status_t, - private_child_delete_t *this, message_t *message) -{ - process_payloads(this, message); - log_children(this); - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_child_delete_t *this, message_t *message) -{ - /* if we are rekeying, we send an empty informational */ - if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING) - { - build_payloads(this, message); - } - DBG1(DBG_IKE, "CHILD_SA closed"); - return destroy_and_reestablish(this); -} - -METHOD(task_t, get_type, task_type_t, - private_child_delete_t *this) -{ - return CHILD_DELETE; -} - -METHOD(child_delete_t , get_child, child_sa_t*, - private_child_delete_t *this) -{ - child_sa_t *child_sa = NULL; - this->child_sas->get_first(this->child_sas, (void**)&child_sa); - return child_sa; -} - -METHOD(task_t, migrate, void, - private_child_delete_t *this, ike_sa_t *ike_sa) -{ - this->check_delete_action = FALSE; - this->ike_sa = ike_sa; - - this->child_sas->destroy(this->child_sas); - this->child_sas = linked_list_create(); -} - -METHOD(task_t, destroy, void, - private_child_delete_t *this) -{ - this->child_sas->destroy(this->child_sas); - free(this); -} - -/* - * Described in header. - */ -child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi) -{ - private_child_delete_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .get_child = _get_child, - }, - .ike_sa = ike_sa, - .child_sas = linked_list_create(), - .protocol = protocol, - .spi = spi, - ); - - if (protocol != PROTO_NONE) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - this->initiator = TRUE; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - this->initiator = FALSE; - } - return &this->public; -} diff --git a/src/libcharon/sa/tasks/child_delete.h b/src/libcharon/sa/tasks/child_delete.h deleted file mode 100644 index 365807c68..000000000 --- a/src/libcharon/sa/tasks/child_delete.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup child_delete child_delete - * @{ @ingroup tasks - */ - -#ifndef CHILD_DELETE_H_ -#define CHILD_DELETE_H_ - -typedef struct child_delete_t child_delete_t; - -#include -#include -#include -#include - -/** - * Task of type child_delete, delete a CHILD_SA. - */ -struct child_delete_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Get the CHILD_SA to delete by this task. - * - * @return child_sa - */ - child_sa_t* (*get_child) (child_delete_t *this); -}; - -/** - * Create a new child_delete task. - * - * @param ike_sa IKE_SA this task works for - * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder - * @param spi inbound SPI of CHILD_SA to delete - * @return child_delete task to handle by the task_manager - */ -child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi); - -#endif /** CHILD_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c deleted file mode 100644 index 76d185590..000000000 --- a/src/libcharon/sa/tasks/child_rekey.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * Copyright (C) 2005-2007 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "child_rekey.h" - -#include -#include -#include -#include -#include -#include - - -typedef struct private_child_rekey_t private_child_rekey_t; - -/** - * Private members of a child_rekey_t task. - */ -struct private_child_rekey_t { - - /** - * Public methods and task_t interface. - */ - child_rekey_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Protocol of CHILD_SA to rekey - */ - protocol_id_t protocol; - - /** - * Inbound SPI of CHILD_SA to rekey - */ - u_int32_t spi; - - /** - * the CHILD_CREATE task which is reused to simplify rekeying - */ - child_create_t *child_create; - - /** - * the CHILD_DELETE task to delete rekeyed CHILD_SA - */ - child_delete_t *child_delete; - - /** - * CHILD_SA which gets rekeyed - */ - child_sa_t *child_sa; - - /** - * colliding task, may be delete or rekey - */ - task_t *collision; - - /** - * Indicate that peer destroyed the redundant child from collision. - * This happens if a peer's delete notification for the redundant - * child gets processed before the rekey job. If so, we must not - * touch the child created in the collision since it points to - * memory already freed. - */ - bool other_child_destroyed; -}; - -/** - * Implementation of task_t.build for initiator, after rekeying - */ -static status_t build_i_delete(private_child_rekey_t *this, message_t *message) -{ - /* update exchange type to INFORMATIONAL for the delete */ - message->set_exchange_type(message, INFORMATIONAL); - - return this->child_delete->task.build(&this->child_delete->task, message); -} - -/** - * Implementation of task_t.process for initiator, after rekeying - */ -static status_t process_i_delete(private_child_rekey_t *this, message_t *message) -{ - return this->child_delete->task.process(&this->child_delete->task, message); -} - -/** - * find a child using the REKEY_SA notify - */ -static void find_child(private_child_rekey_t *this, message_t *message) -{ - notify_payload_t *notify; - protocol_id_t protocol; - u_int32_t spi; - - notify = message->get_notify(message, REKEY_SA); - if (notify) - { - protocol = notify->get_protocol_id(notify); - spi = notify->get_spi(notify); - - if (protocol == PROTO_ESP || protocol == PROTO_AH) - { - this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, - spi, FALSE); - } - } -} - -METHOD(task_t, build_i, status_t, - private_child_rekey_t *this, message_t *message) -{ - notify_payload_t *notify; - u_int32_t reqid; - child_cfg_t *config; - - this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, - this->spi, TRUE); - if (!this->child_sa) - { /* check if it is an outbound CHILD_SA */ - this->child_sa = this->ike_sa->get_child_sa(this->ike_sa, this->protocol, - this->spi, FALSE); - if (!this->child_sa) - { /* CHILD_SA is gone, unable to rekey. As an empty CREATE_CHILD_SA - * exchange is invalid, we fall back to an INFORMATIONAL exchange.*/ - message->set_exchange_type(message, INFORMATIONAL); - return SUCCESS; - } - /* we work only with the inbound SPI */ - this->spi = this->child_sa->get_spi(this->child_sa, TRUE); - } - config = this->child_sa->get_config(this->child_sa); - - /* we just need the rekey notify ... */ - notify = notify_payload_create_from_protocol_and_type(this->protocol, - REKEY_SA); - notify->set_spi(notify, this->spi); - message->add_payload(message, (payload_t*)notify); - - /* ... our CHILD_CREATE task does the hard work for us. */ - if (!this->child_create) - { - this->child_create = child_create_create(this->ike_sa, config, TRUE, - NULL, NULL); - } - reqid = this->child_sa->get_reqid(this->child_sa); - this->child_create->use_reqid(this->child_create, reqid); - this->child_create->task.build(&this->child_create->task, message); - - this->child_sa->set_state(this->child_sa, CHILD_REKEYING); - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_child_rekey_t *this, message_t *message) -{ - /* let the CHILD_CREATE task process the message */ - this->child_create->task.process(&this->child_create->task, message); - - find_child(this, message); - - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_child_rekey_t *this, message_t *message) -{ - u_int32_t reqid; - - if (this->child_sa == NULL || - this->child_sa->get_state(this->child_sa) == CHILD_DELETING) - { - DBG1(DBG_IKE, "unable to rekey, CHILD_SA not found"); - message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); - return SUCCESS; - } - - /* let the CHILD_CREATE task build the response */ - reqid = this->child_sa->get_reqid(this->child_sa); - this->child_create->use_reqid(this->child_create, reqid); - this->child_create->task.build(&this->child_create->task, message); - - if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) - { - /* rekeying failed, reuse old child */ - this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - return SUCCESS; - } - - this->child_sa->set_state(this->child_sa, CHILD_REKEYING); - - /* invoke rekey hook */ - charon->bus->child_rekey(charon->bus, this->child_sa, - this->child_create->get_child(this->child_create)); - return SUCCESS; -} - -/** - * Handle a rekey collision - */ -static child_sa_t *handle_collision(private_child_rekey_t *this) -{ - child_sa_t *to_delete; - - if (this->collision->get_type(this->collision) == CHILD_REKEY) - { - chunk_t this_nonce, other_nonce; - private_child_rekey_t *other = (private_child_rekey_t*)this->collision; - - this_nonce = this->child_create->get_lower_nonce(this->child_create); - other_nonce = other->child_create->get_lower_nonce(other->child_create); - - /* if we have the lower nonce, delete rekeyed SA. If not, delete - * the redundant. */ - if (memcmp(this_nonce.ptr, other_nonce.ptr, - min(this_nonce.len, other_nonce.len)) > 0) - { - child_sa_t *child_sa; - - DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child"); - to_delete = this->child_sa; - /* don't touch child other created, it has already been deleted */ - if (!this->other_child_destroyed) - { - /* disable close action for the redundand child */ - child_sa = other->child_create->get_child(other->child_create); - if (child_sa) - { - child_sa->set_close_action(child_sa, ACTION_NONE); - } - } - } - else - { - DBG1(DBG_IKE, "CHILD_SA rekey collision lost, " - "deleting rekeyed child"); - to_delete = this->child_create->get_child(this->child_create); - } - } - else - { /* CHILD_DELETE */ - child_delete_t *del = (child_delete_t*)this->collision; - - /* we didn't had a chance to compare the nonces, so we delete - * the CHILD_SA the other is not deleting. */ - if (del->get_child(del) != this->child_sa) - { - DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, " - "deleting rekeyed child"); - to_delete = this->child_sa; - } - else - { - DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, " - "deleting redundant child"); - to_delete = this->child_create->get_child(this->child_create); - } - } - return to_delete; -} - -METHOD(task_t, process_i, status_t, - private_child_rekey_t *this, message_t *message) -{ - protocol_id_t protocol; - u_int32_t spi; - child_sa_t *to_delete; - - if (message->get_notify(message, NO_ADDITIONAL_SAS)) - { - DBG1(DBG_IKE, "peer seems to not support CHILD_SA rekeying, " - "starting reauthentication"); - this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - lib->processor->queue_job(lib->processor, - (job_t*)rekey_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), TRUE)); - return SUCCESS; - } - - if (this->child_create->task.process(&this->child_create->task, - message) == NEED_MORE) - { - /* bad DH group while rekeying, try again */ - this->child_create->task.migrate(&this->child_create->task, this->ike_sa); - return NEED_MORE; - } - if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) - { - /* establishing new child failed, reuse old. but not when we - * received a delete in the meantime */ - if (!(this->collision && - this->collision->get_type(this->collision) == CHILD_DELETE)) - { - job_t *job; - u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); - - job = (job_t*)rekey_child_sa_job_create( - this->child_sa->get_reqid(this->child_sa), - this->child_sa->get_protocol(this->child_sa), - this->child_sa->get_spi(this->child_sa, TRUE)); - DBG1(DBG_IKE, "CHILD_SA rekeying failed, " - "trying again in %d seconds", retry); - this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); - lib->scheduler->schedule_job(lib->scheduler, job, retry); - } - return SUCCESS; - } - - /* check for rekey collisions */ - if (this->collision) - { - to_delete = handle_collision(this); - } - else - { - to_delete = this->child_sa; - } - - if (to_delete != this->child_create->get_child(this->child_create)) - { /* invoke rekey hook if rekeying successful */ - charon->bus->child_rekey(charon->bus, this->child_sa, - this->child_create->get_child(this->child_create)); - } - - if (to_delete == NULL) - { - return SUCCESS; - } - spi = to_delete->get_spi(to_delete, TRUE); - protocol = to_delete->get_protocol(to_delete); - - /* rekeying done, delete the obsolete CHILD_SA using a subtask */ - this->child_delete = child_delete_create(this->ike_sa, protocol, spi); - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete; - - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_child_rekey_t *this) -{ - return CHILD_REKEY; -} - -METHOD(child_rekey_t, collide, void, - private_child_rekey_t *this, task_t *other) -{ - /* the task manager only detects exchange collision, but not if - * the collision is for the same child. we check it here. */ - if (other->get_type(other) == CHILD_REKEY) - { - private_child_rekey_t *rekey = (private_child_rekey_t*)other; - if (rekey->child_sa != this->child_sa) - { - /* not the same child => no collision */ - other->destroy(other); - return; - } - } - else if (other->get_type(other) == CHILD_DELETE) - { - child_delete_t *del = (child_delete_t*)other; - if (del->get_child(del) == this->child_create->get_child(this->child_create)) - { - /* peer deletes redundant child created in collision */ - this->other_child_destroyed = TRUE; - other->destroy(other); - return; - } - if (del->get_child(del) != this->child_sa) - { - /* not the same child => no collision */ - other->destroy(other); - return; - } - } - else - { - /* any other task is not critical for collisisions, ignore */ - other->destroy(other); - return; - } - DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, CHILD_REKEY, - task_type_names, other->get_type(other)); - DESTROY_IF(this->collision); - this->collision = other; -} - -METHOD(task_t, migrate, void, - private_child_rekey_t *this, ike_sa_t *ike_sa) -{ - if (this->child_create) - { - this->child_create->task.migrate(&this->child_create->task, ike_sa); - } - if (this->child_delete) - { - this->child_delete->task.migrate(&this->child_delete->task, ike_sa); - } - DESTROY_IF(this->collision); - - this->ike_sa = ike_sa; - this->collision = NULL; -} - -METHOD(task_t, destroy, void, - private_child_rekey_t *this) -{ - if (this->child_create) - { - this->child_create->task.destroy(&this->child_create->task); - } - if (this->child_delete) - { - this->child_delete->task.destroy(&this->child_delete->task); - } - DESTROY_IF(this->collision); - free(this); -} - -/* - * Described in header. - */ -child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi) -{ - private_child_rekey_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .collide = _collide, - }, - .ike_sa = ike_sa, - .protocol = protocol, - .spi = spi, - ); - - if (protocol != PROTO_NONE) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - this->initiator = TRUE; - this->child_create = NULL; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - this->initiator = FALSE; - this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL); - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/child_rekey.h b/src/libcharon/sa/tasks/child_rekey.h deleted file mode 100644 index 9b1aea5fa..000000000 --- a/src/libcharon/sa/tasks/child_rekey.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup child_rekey child_rekey - * @{ @ingroup tasks - */ - -#ifndef CHILD_REKEY_H_ -#define CHILD_REKEY_H_ - -typedef struct child_rekey_t child_rekey_t; - -#include -#include -#include -#include - -/** - * Task of type CHILD_REKEY, rekey an established CHILD_SA. - */ -struct child_rekey_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Register a rekeying task which collides with this one - * - * If two peers initiate rekeying at the same time, the collision must - * be handled gracefully. The task manager is aware of what exchanges - * are going on and notifies the outgoing task by passing the incoming. - * - * @param other incoming task - */ - void (*collide)(child_rekey_t* this, task_t *other); -}; - -/** - * Create a new CHILD_REKEY task. - * - * @param ike_sa IKE_SA this task works for - * @param protocol protocol of CHILD_SA to rekey, PROTO_NONE as responder - * @param spi inbound SPI of CHILD_SA to rekey - * @return child_rekey task to handle by the task_manager - */ -child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi); - -#endif /** CHILD_REKEY_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c deleted file mode 100644 index 665468fe8..000000000 --- a/src/libcharon/sa/tasks/ike_auth.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Copyright (C) 2005-2009 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details - */ - -#include "ike_auth.h" - -#include - -#include -#include -#include -#include -#include -#include - -typedef struct private_ike_auth_t private_ike_auth_t; - -/** - * Private members of a ike_auth_t task. - */ -struct private_ike_auth_t { - - /** - * Public methods and task_t interface. - */ - ike_auth_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Nonce chosen by us in ike_init - */ - chunk_t my_nonce; - - /** - * Nonce chosen by peer in ike_init - */ - chunk_t other_nonce; - - /** - * IKE_SA_INIT message sent by us - */ - packet_t *my_packet; - - /** - * IKE_SA_INIT message sent by peer - */ - packet_t *other_packet; - - /** - * Reserved bytes of ID payload - */ - char reserved[3]; - - /** - * currently active authenticator, to authenticate us - */ - authenticator_t *my_auth; - - /** - * currently active authenticator, to authenticate peer - */ - authenticator_t *other_auth; - - /** - * peer_cfg candidates, ordered by priority - */ - linked_list_t *candidates; - - /** - * selected peer config (might change when using multiple authentications) - */ - peer_cfg_t *peer_cfg; - - /** - * have we planned an(other) authentication exchange? - */ - bool do_another_auth; - - /** - * has the peer announced another authentication exchange? - */ - bool expect_another_auth; - - /** - * should we send a AUTHENTICATION_FAILED notify? - */ - bool authentication_failed; - - /** - * received an INITIAL_CONTACT? - */ - bool initial_contact; -}; - -/** - * check if multiple authentication extension is enabled, configuration-wise - */ -static bool multiple_auth_enabled() -{ - return lib->settings->get_bool(lib->settings, - "charon.multiple_authentication", TRUE); -} - -/** - * collect the needed information in the IKE_SA_INIT exchange from our message - */ -static status_t collect_my_init_data(private_ike_auth_t *this, - message_t *message) -{ - nonce_payload_t *nonce; - - /* get the nonce that was generated in ike_init */ - nonce = (nonce_payload_t*)message->get_payload(message, NONCE); - if (nonce == NULL) - { - return FAILED; - } - this->my_nonce = nonce->get_nonce(nonce); - - /* pre-generate the message, keep a copy */ - if (this->ike_sa->generate_message(this->ike_sa, message, - &this->my_packet) != SUCCESS) - { - return FAILED; - } - return NEED_MORE; -} - -/** - * collect the needed information in the IKE_SA_INIT exchange from others message - */ -static status_t collect_other_init_data(private_ike_auth_t *this, - message_t *message) -{ - /* we collect the needed information in the IKE_SA_INIT exchange */ - nonce_payload_t *nonce; - - /* get the nonce that was generated in ike_init */ - nonce = (nonce_payload_t*)message->get_payload(message, NONCE); - if (nonce == NULL) - { - return FAILED; - } - this->other_nonce = nonce->get_nonce(nonce); - - /* keep a copy of the received packet */ - this->other_packet = message->get_packet(message); - return NEED_MORE; -} - -/** - * Get and store reserved bytes of id_payload, required for AUTH payload - */ -static void get_reserved_id_bytes(private_ike_auth_t *this, id_payload_t *id) -{ - u_int8_t *byte; - int i; - - for (i = 0; i < countof(this->reserved); i++) - { - byte = payload_get_field(&id->payload_interface, RESERVED_BYTE, i); - if (byte) - { - this->reserved[i] = *byte; - } - } -} - -/** - * Get the next authentication configuration - */ -static auth_cfg_t *get_auth_cfg(private_ike_auth_t *this, bool local) -{ - enumerator_t *e1, *e2; - auth_cfg_t *c1, *c2, *next = NULL; - - /* find an available config not already done */ - e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, local); - while (e1->enumerate(e1, &c1)) - { - bool found = FALSE; - - e2 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, local); - while (e2->enumerate(e2, &c2)) - { - if (c2->complies(c2, c1, FALSE)) - { - found = TRUE; - break; - } - } - e2->destroy(e2); - if (!found) - { - next = c1; - break; - } - } - e1->destroy(e1); - return next; -} - -/** - * Check if we have should initiate another authentication round - */ -static bool do_another_auth(private_ike_auth_t *this) -{ - bool do_another = FALSE; - enumerator_t *done, *todo; - auth_cfg_t *done_cfg, *todo_cfg; - - if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) - { - return FALSE; - } - - done = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, TRUE); - todo = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, TRUE); - while (todo->enumerate(todo, &todo_cfg)) - { - if (!done->enumerate(done, &done_cfg)) - { - done_cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - } - if (!done_cfg->complies(done_cfg, todo_cfg, FALSE)) - { - do_another = TRUE; - break; - } - } - done->destroy(done); - todo->destroy(todo); - return do_another; -} - -/** - * Get peer configuration candidates from backends - */ -static bool load_cfg_candidates(private_ike_auth_t *this) -{ - enumerator_t *enumerator; - peer_cfg_t *peer_cfg; - host_t *me, *other; - identification_t *my_id, *other_id; - - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - my_id = this->ike_sa->get_my_id(this->ike_sa); - other_id = this->ike_sa->get_other_id(this->ike_sa); - - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - me, other, my_id, other_id); - while (enumerator->enumerate(enumerator, &peer_cfg)) - { - peer_cfg->get_ref(peer_cfg); - if (this->peer_cfg == NULL) - { /* best match */ - this->peer_cfg = peer_cfg; - this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg); - } - else - { - this->candidates->insert_last(this->candidates, peer_cfg); - } - } - enumerator->destroy(enumerator); - if (this->peer_cfg) - { - DBG1(DBG_CFG, "selected peer config '%s'", - this->peer_cfg->get_name(this->peer_cfg)); - return TRUE; - } - DBG1(DBG_CFG, "no matching peer config found"); - return FALSE; -} - -/** - * update the current peer candidate if necessary, using candidates - */ -static bool update_cfg_candidates(private_ike_auth_t *this, bool strict) -{ - do - { - if (this->peer_cfg) - { - bool complies = TRUE; - enumerator_t *e1, *e2, *tmp; - auth_cfg_t *c1, *c2; - - e1 = this->ike_sa->create_auth_cfg_enumerator(this->ike_sa, FALSE); - e2 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE); - - if (strict) - { /* swap lists in strict mode: all configured rounds must be - * fulfilled. If !strict, we check only the rounds done so far. */ - tmp = e1; - e1 = e2; - e2 = tmp; - } - while (e1->enumerate(e1, &c1)) - { - /* check if done authentications comply to configured ones */ - if ((!e2->enumerate(e2, &c2)) || - (!strict && !c1->complies(c1, c2, TRUE)) || - (strict && !c2->complies(c2, c1, TRUE))) - { - complies = FALSE; - break; - } - } - e1->destroy(e1); - e2->destroy(e2); - if (complies) - { - break; - } - DBG1(DBG_CFG, "selected peer config '%s' inacceptable", - this->peer_cfg->get_name(this->peer_cfg)); - this->peer_cfg->destroy(this->peer_cfg); - } - if (this->candidates->remove_first(this->candidates, - (void**)&this->peer_cfg) != SUCCESS) - { - DBG1(DBG_CFG, "no alternative config found"); - this->peer_cfg = NULL; - } - else - { - DBG1(DBG_CFG, "switching to peer config '%s'", - this->peer_cfg->get_name(this->peer_cfg)); - this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); - } - } - while (this->peer_cfg); - - return this->peer_cfg != NULL; -} - -METHOD(task_t, build_i, status_t, - private_ike_auth_t *this, message_t *message) -{ - auth_cfg_t *cfg; - - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return collect_my_init_data(this, message); - } - - if (this->peer_cfg == NULL) - { - this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - this->peer_cfg->get_ref(this->peer_cfg); - } - - if (message->get_message_id(message) == 1) - { /* in the first IKE_AUTH ... */ - if (this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) - { /* indicate support for multiple authentication */ - message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, - chunk_empty); - } - /* indicate support for EAP-only authentication */ - message->add_notify(message, FALSE, EAP_ONLY_AUTHENTICATION, - chunk_empty); - } - - if (!this->do_another_auth && !this->my_auth) - { /* we have done our rounds */ - return NEED_MORE; - } - - /* check if an authenticator is in progress */ - if (this->my_auth == NULL) - { - identification_t *idi, *idr = NULL; - id_payload_t *id_payload; - - /* clean up authentication config from a previous round */ - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - cfg->purge(cfg, TRUE); - - /* add (optional) IDr */ - cfg = get_auth_cfg(this, FALSE); - if (cfg) - { - idr = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (idr && !idr->contains_wildcards(idr)) - { - this->ike_sa->set_other_id(this->ike_sa, idr->clone(idr)); - id_payload = id_payload_create_from_identification( - ID_RESPONDER, idr); - message->add_payload(message, (payload_t*)id_payload); - } - } - /* add IDi */ - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); - idi = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (!idi || idi->get_type(idi) == ID_ANY) - { /* ID_ANY is invalid as IDi, use local IP address instead */ - host_t *me; - - DBG1(DBG_CFG, "no IDi configured, fall back on IP address"); - me = this->ike_sa->get_my_host(this->ike_sa); - idi = identification_create_from_sockaddr(me->get_sockaddr(me)); - cfg->add(cfg, AUTH_RULE_IDENTITY, idi); - } - this->ike_sa->set_my_id(this->ike_sa, idi->clone(idi)); - id_payload = id_payload_create_from_identification(ID_INITIATOR, idi); - get_reserved_id_bytes(this, id_payload); - message->add_payload(message, (payload_t*)id_payload); - - if (idr && message->get_message_id(message) == 1 && - this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO) - { - host_t *host; - - host = this->ike_sa->get_other_host(this->ike_sa); - if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager, - idi, idr, host->get_family(host))) - { - message->add_notify(message, FALSE, INITIAL_CONTACT, chunk_empty); - } - } - - /* build authentication data */ - this->my_auth = authenticator_create_builder(this->ike_sa, cfg, - this->other_nonce, this->my_nonce, - this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet), - this->reserved); - if (!this->my_auth) - { - return FAILED; - } - } - switch (this->my_auth->build(this->my_auth, message)) - { - case SUCCESS: - /* authentication step complete, reset authenticator */ - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), TRUE); - this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); - this->my_auth->destroy(this->my_auth); - this->my_auth = NULL; - break; - case NEED_MORE: - break; - default: - return FAILED; - } - - /* check for additional authentication rounds */ - if (do_another_auth(this)) - { - if (message->get_payload(message, AUTHENTICATION)) - { - message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); - } - } - else - { - this->do_another_auth = FALSE; - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_auth_t *this, message_t *message) -{ - auth_cfg_t *cfg, *cand; - id_payload_t *id_payload; - identification_t *id; - - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return collect_other_init_data(this, message); - } - - if (this->my_auth == NULL && this->do_another_auth) - { - /* handle (optional) IDr payload, apply proposed identity */ - id_payload = (id_payload_t*)message->get_payload(message, ID_RESPONDER); - if (id_payload) - { - id = id_payload->get_identification(id_payload); - } - else - { - id = identification_create_from_encoding(ID_ANY, chunk_empty); - } - this->ike_sa->set_my_id(this->ike_sa, id); - } - - if (!this->expect_another_auth) - { - return NEED_MORE; - } - - if (message->get_message_id(message) == 1) - { /* check for extensions in the first IKE_AUTH */ - if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED)) - { - this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); - } - if (message->get_notify(message, EAP_ONLY_AUTHENTICATION)) - { - this->ike_sa->enable_extension(this->ike_sa, - EXT_EAP_ONLY_AUTHENTICATION); - } - } - - if (this->other_auth == NULL) - { - /* handle IDi payload */ - id_payload = (id_payload_t*)message->get_payload(message, ID_INITIATOR); - if (!id_payload) - { - DBG1(DBG_IKE, "IDi payload missing"); - return FAILED; - } - id = id_payload->get_identification(id_payload); - get_reserved_id_bytes(this, id_payload); - this->ike_sa->set_other_id(this->ike_sa, id); - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); - - if (this->peer_cfg == NULL) - { - if (!load_cfg_candidates(this)) - { - this->authentication_failed = TRUE; - return NEED_MORE; - } - } - if (message->get_payload(message, AUTHENTICATION) == NULL) - { /* before authenticating with EAP, we need a EAP config */ - cand = get_auth_cfg(this, FALSE); - while (!cand || ( - (uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK && - (uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0)) - { /* peer requested EAP, but current config does not match */ - DBG1(DBG_IKE, "peer requested EAP, config inacceptable"); - this->peer_cfg->destroy(this->peer_cfg); - this->peer_cfg = NULL; - if (!update_cfg_candidates(this, FALSE)) - { - this->authentication_failed = TRUE; - return NEED_MORE; - } - cand = get_auth_cfg(this, FALSE); - } - /* copy over the EAP specific rules for authentication */ - cfg->add(cfg, AUTH_RULE_EAP_TYPE, - cand->get(cand, AUTH_RULE_EAP_TYPE)); - cfg->add(cfg, AUTH_RULE_EAP_VENDOR, - cand->get(cand, AUTH_RULE_EAP_VENDOR)); - id = (identification_t*)cand->get(cand, AUTH_RULE_EAP_IDENTITY); - if (id) - { - cfg->add(cfg, AUTH_RULE_EAP_IDENTITY, id->clone(id)); - } - id = (identification_t*)cand->get(cand, AUTH_RULE_AAA_IDENTITY); - if (id) - { - cfg->add(cfg, AUTH_RULE_AAA_IDENTITY, id->clone(id)); - } - } - - /* verify authentication data */ - this->other_auth = authenticator_create_verifier(this->ike_sa, - message, this->other_nonce, this->my_nonce, - this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet), - this->reserved); - if (!this->other_auth) - { - this->authentication_failed = TRUE; - return NEED_MORE; - } - } - switch (this->other_auth->process(this->other_auth, message)) - { - case SUCCESS: - this->other_auth->destroy(this->other_auth); - this->other_auth = NULL; - break; - case NEED_MORE: - if (message->get_payload(message, AUTHENTICATION)) - { /* AUTH verification successful, but another build() needed */ - break; - } - return NEED_MORE; - default: - this->authentication_failed = TRUE; - return NEED_MORE; - } - - /* If authenticated (with non-EAP) and received INITIAL_CONTACT, - * delete any existing IKE_SAs with that peer. */ - if (message->get_message_id(message) == 1 && - message->get_notify(message, INITIAL_CONTACT)) - { - this->initial_contact = TRUE; - } - - /* another auth round done, invoke authorize hook */ - if (!charon->bus->authorize(charon->bus, FALSE)) - { - DBG1(DBG_IKE, "authorization hook forbids IKE_SA, cancelling"); - this->authentication_failed = TRUE; - return NEED_MORE; - } - - /* store authentication information */ - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); - this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); - - if (!update_cfg_candidates(this, FALSE)) - { - this->authentication_failed = TRUE; - return NEED_MORE; - } - - if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) - { - this->expect_another_auth = FALSE; - if (!update_cfg_candidates(this, TRUE)) - { - this->authentication_failed = TRUE; - return NEED_MORE; - } - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_auth_t *this, message_t *message) -{ - auth_cfg_t *cfg; - - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - if (multiple_auth_enabled()) - { - message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, - chunk_empty); - } - return collect_my_init_data(this, message); - } - - if (this->authentication_failed || this->peer_cfg == NULL) - { - goto peer_auth_failed; - } - - if (this->my_auth == NULL && this->do_another_auth) - { - identification_t *id, *id_cfg; - id_payload_t *id_payload; - - /* add IDr */ - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - cfg->purge(cfg, TRUE); - cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); - - id_cfg = cfg->get(cfg, AUTH_RULE_IDENTITY); - id = this->ike_sa->get_my_id(this->ike_sa); - if (id->get_type(id) == ID_ANY) - { /* no IDr received, apply configured ID */ - if (!id_cfg || id_cfg->contains_wildcards(id_cfg)) - { /* no ID configured, use local IP address */ - host_t *me; - - DBG1(DBG_CFG, "no IDr configured, fall back on IP address"); - me = this->ike_sa->get_my_host(this->ike_sa); - id_cfg = identification_create_from_sockaddr( - me->get_sockaddr(me)); - cfg->add(cfg, AUTH_RULE_IDENTITY, id_cfg); - } - this->ike_sa->set_my_id(this->ike_sa, id_cfg->clone(id_cfg)); - id = id_cfg; - } - else - { /* IDr received, check if it matches configuration */ - if (id_cfg && !id->matches(id, id_cfg)) - { - DBG1(DBG_CFG, "received IDr %Y, but require %Y", id, id_cfg); - goto peer_auth_failed; - } - } - - id_payload = id_payload_create_from_identification(ID_RESPONDER, id); - get_reserved_id_bytes(this, id_payload); - message->add_payload(message, (payload_t*)id_payload); - - if (this->initial_contact) - { - charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa, TRUE); - this->initial_contact = FALSE; - } - - if ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS) == AUTH_CLASS_EAP) - { /* EAP-only authentication */ - if (!this->ike_sa->supports_extension(this->ike_sa, - EXT_EAP_ONLY_AUTHENTICATION)) - { - DBG1(DBG_IKE, "configured EAP-only authentication, but peer " - "does not support it"); - goto peer_auth_failed; - } - } - else - { - /* build authentication data */ - this->my_auth = authenticator_create_builder(this->ike_sa, cfg, - this->other_nonce, this->my_nonce, - this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet), - this->reserved); - if (!this->my_auth) - { - goto peer_auth_failed; - } - } - } - - if (this->other_auth) - { - switch (this->other_auth->build(this->other_auth, message)) - { - case SUCCESS: - this->other_auth->destroy(this->other_auth); - this->other_auth = NULL; - break; - case NEED_MORE: - break; - default: - if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { /* skip AUTHENTICATION_FAILED if we have EAP_FAILURE */ - goto peer_auth_failed_no_notify; - } - goto peer_auth_failed; - } - } - if (this->my_auth) - { - switch (this->my_auth->build(this->my_auth, message)) - { - case SUCCESS: - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), - TRUE); - this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); - this->my_auth->destroy(this->my_auth); - this->my_auth = NULL; - break; - case NEED_MORE: - break; - default: - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; - } - } - - /* check for additional authentication rounds */ - if (do_another_auth(this)) - { - message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); - } - else - { - this->do_another_auth = FALSE; - } - if (!this->do_another_auth && !this->expect_another_auth) - { - if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa, FALSE)) - { - DBG1(DBG_IKE, "cancelling IKE_SA setup due to uniqueness policy"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); - return FAILED; - } - if (!charon->bus->authorize(charon->bus, TRUE)) - { - DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); - goto peer_auth_failed; - } - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - return SUCCESS; - } - return NEED_MORE; - -peer_auth_failed: - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, - chunk_empty); -peer_auth_failed_no_notify: - charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); - return FAILED; -} - -METHOD(task_t, process_i, status_t, - private_ike_auth_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - auth_cfg_t *cfg; - bool mutual_eap = FALSE; - - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED) && - multiple_auth_enabled()) - { - this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); - } - return collect_other_init_data(this, message); - } - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == NOTIFY) - { - notify_payload_t *notify = (notify_payload_t*)payload; - notify_type_t type = notify->get_notify_type(notify); - - switch (type) - { - case NO_PROPOSAL_CHOSEN: - case SINGLE_PAIR_REQUIRED: - case NO_ADDITIONAL_SAS: - case INTERNAL_ADDRESS_FAILURE: - case FAILED_CP_REQUIRED: - case TS_UNACCEPTABLE: - case INVALID_SELECTORS: - /* these are errors, but are not critical as only the - * CHILD_SA won't get build, but IKE_SA establishes anyway */ - break; - case MOBIKE_SUPPORTED: - case ADDITIONAL_IP4_ADDRESS: - case ADDITIONAL_IP6_ADDRESS: - /* handled in ike_mobike task */ - break; - case AUTH_LIFETIME: - /* handled in ike_auth_lifetime task */ - break; - case ME_ENDPOINT: - /* handled in ike_me task */ - break; - default: - { - if (type <= 16383) - { - DBG1(DBG_IKE, "received %N notify error", - notify_type_names, type); - enumerator->destroy(enumerator); - return FAILED; - } - DBG2(DBG_IKE, "received %N notify", - notify_type_names, type); - break; - } - } - } - } - enumerator->destroy(enumerator); - - if (this->expect_another_auth) - { - if (this->other_auth == NULL) - { - id_payload_t *id_payload; - identification_t *id; - - /* handle IDr payload */ - id_payload = (id_payload_t*)message->get_payload(message, - ID_RESPONDER); - if (!id_payload) - { - DBG1(DBG_IKE, "IDr payload missing"); - goto peer_auth_failed; - } - id = id_payload->get_identification(id_payload); - get_reserved_id_bytes(this, id_payload); - this->ike_sa->set_other_id(this->ike_sa, id); - cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); - - if (message->get_payload(message, AUTHENTICATION)) - { - /* verify authentication data */ - this->other_auth = authenticator_create_verifier(this->ike_sa, - message, this->other_nonce, this->my_nonce, - this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet), - this->reserved); - if (!this->other_auth) - { - goto peer_auth_failed; - } - } - else - { - /* responder omitted AUTH payload, indicating EAP-only */ - mutual_eap = TRUE; - } - } - if (this->other_auth) - { - switch (this->other_auth->process(this->other_auth, message)) - { - case SUCCESS: - break; - case NEED_MORE: - return NEED_MORE; - default: - goto peer_auth_failed; - } - this->other_auth->destroy(this->other_auth); - this->other_auth = NULL; - } - /* another auth round done, invoke authorize hook */ - if (!charon->bus->authorize(charon->bus, FALSE)) - { - DBG1(DBG_IKE, "authorization forbids IKE_SA, cancelling"); - goto peer_auth_failed; - } - - /* store authentication information, reset authenticator */ - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); - this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); - } - - if (this->my_auth) - { - switch (this->my_auth->process(this->my_auth, message)) - { - case SUCCESS: - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), - TRUE); - this->ike_sa->add_auth_cfg(this->ike_sa, TRUE, cfg); - this->my_auth->destroy(this->my_auth); - this->my_auth = NULL; - this->do_another_auth = do_another_auth(this); - break; - case NEED_MORE: - break; - default: - return FAILED; - } - } - if (mutual_eap) - { - if (!this->my_auth || !this->my_auth->is_mutual(this->my_auth)) - { - DBG1(DBG_IKE, "do not allow non-mutual EAP-only authentication"); - goto peer_auth_failed; - } - DBG1(DBG_IKE, "allow mutual EAP-only authentication"); - } - - if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) - { - this->expect_another_auth = FALSE; - } - if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth) - { - if (!update_cfg_candidates(this, TRUE)) - { - goto peer_auth_failed; - } - if (!charon->bus->authorize(charon->bus, TRUE)) - { - DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, " - "cancelling"); - goto peer_auth_failed; - } - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - return SUCCESS; - } - return NEED_MORE; - -peer_auth_failed: - charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED); - return FAILED; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_auth_t *this) -{ - return IKE_AUTHENTICATE; -} - -METHOD(task_t, migrate, void, - private_ike_auth_t *this, ike_sa_t *ike_sa) -{ - chunk_free(&this->my_nonce); - chunk_free(&this->other_nonce); - DESTROY_IF(this->my_packet); - DESTROY_IF(this->other_packet); - DESTROY_IF(this->peer_cfg); - DESTROY_IF(this->my_auth); - DESTROY_IF(this->other_auth); - this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); - - this->my_packet = NULL; - this->other_packet = NULL; - this->ike_sa = ike_sa; - this->peer_cfg = NULL; - this->my_auth = NULL; - this->other_auth = NULL; - this->do_another_auth = TRUE; - this->expect_another_auth = TRUE; - this->authentication_failed = FALSE; - this->candidates = linked_list_create(); -} - -METHOD(task_t, destroy, void, - private_ike_auth_t *this) -{ - chunk_free(&this->my_nonce); - chunk_free(&this->other_nonce); - DESTROY_IF(this->my_packet); - DESTROY_IF(this->other_packet); - DESTROY_IF(this->my_auth); - DESTROY_IF(this->other_auth); - DESTROY_IF(this->peer_cfg); - this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); - free(this); -} - -/* - * Described in header. - */ -ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_auth_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .build = _build_r, - .process = _process_r, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .initiator = initiator, - .candidates = linked_list_create(), - .do_another_auth = TRUE, - .expect_another_auth = TRUE, - ); - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_auth.h b/src/libcharon/sa/tasks/ike_auth.h deleted file mode 100644 index 132907941..000000000 --- a/src/libcharon/sa/tasks/ike_auth.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_auth ike_auth - * @{ @ingroup tasks - */ - -#ifndef IKE_AUTH_H_ -#define IKE_AUTH_H_ - -typedef struct ike_auth_t ike_auth_t; - -#include -#include -#include - -/** - * Task of type ike_auth, authenticates an IKE_SA using authenticators. - * - * The ike_auth task authenticates the IKE_SA using the IKE_AUTH - * exchange. It processes and build IDi and IDr payloads and also - * handles AUTH payloads. The AUTH payloads are passed to authenticator_t's, - * which do the actual authentication process. If the ike_auth task is used - * with EAP authentication, it stays alive over multiple exchanges until - * EAP has completed. - */ -struct ike_auth_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new task of type IKE_AUTHENTICATE. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is the initiator of an exchange - * @return ike_auth task to handle by the task_manager - */ -ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_AUTH_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.c b/src/libcharon/sa/tasks/ike_auth_lifetime.c deleted file mode 100644 index a57cfd075..000000000 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_auth_lifetime.h" - -#include - -#include -#include - - -typedef struct private_ike_auth_lifetime_t private_ike_auth_lifetime_t; - -/** - * Private members of a ike_auth_lifetime_t task. - */ -struct private_ike_auth_lifetime_t { - - /** - * Public methods and task_t interface. - */ - ike_auth_lifetime_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; -}; - -/** - * add the AUTH_LIFETIME notify to the message - */ -static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *message) -{ - chunk_t chunk; - u_int32_t lifetime; - - lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH); - if (lifetime) - { - lifetime -= time_monotonic(NULL); - chunk = chunk_from_thing(lifetime); - *(u_int32_t*)chunk.ptr = htonl(lifetime); - message->add_notify(message, FALSE, AUTH_LIFETIME, chunk); - } -} - -/** - * read notifys from message and evaluate them - */ -static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message) -{ - notify_payload_t *notify; - chunk_t data; - u_int32_t lifetime; - - notify = message->get_notify(message, AUTH_LIFETIME); - if (notify) - { - data = notify->get_notification_data(notify); - lifetime = ntohl(*(u_int32_t*)data.ptr); - this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime); - } -} - -METHOD(task_t, build_i, status_t, - private_ike_auth_lifetime_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == INFORMATIONAL) - { - add_auth_lifetime(this, message); - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_auth_lifetime_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == INFORMATIONAL) - { - process_payloads(this, message); - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_auth_lifetime_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { - add_auth_lifetime(this, message); - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_auth_lifetime_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { - process_payloads(this, message); - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_auth_lifetime_t *this) -{ - return IKE_AUTH_LIFETIME; -} - -METHOD(task_t, migrate, void, - private_ike_auth_lifetime_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; -} - -METHOD(task_t, destroy, void, - private_ike_auth_lifetime_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_auth_lifetime_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.h b/src/libcharon/sa/tasks/ike_auth_lifetime.h deleted file mode 100644 index 3b129b9e3..000000000 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_auth_lifetime ike_auth_lifetime - * @{ @ingroup tasks - */ - -#ifndef IKE_AUTH_LIFETIME_H_ -#define IKE_AUTH_LIFETIME_H_ - -typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; - -#include -#include -#include - -/** - * Task of type IKE_AUTH_LIFETIME, implements RFC4478. - * - * This task exchanges lifetimes for IKE_AUTH to force a client to - * reauthenticate before the responders lifetime reaches the limit. - */ -struct ike_auth_lifetime_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new IKE_AUTH_LIFETIME task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if taks is initiated by us - * @return ike_auth_lifetime task to handle by the task_manager - */ -ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_MOBIKE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c deleted file mode 100644 index 94af50eae..000000000 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_cert_post.h" - -#include -#include -#include -#include -#include -#include - - -typedef struct private_ike_cert_post_t private_ike_cert_post_t; - -/** - * Private members of a ike_cert_post_t task. - */ -struct private_ike_cert_post_t { - - /** - * Public methods and task_t interface. - */ - ike_cert_post_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; -}; - -/** - * Generates the cert payload, if possible with "Hash and URL" - */ -static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, - certificate_t *cert) -{ - hasher_t *hasher; - identification_t *id; - chunk_t hash, encoded ; - enumerator_t *enumerator; - char *url; - cert_payload_t *payload = NULL; - - if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) - { - return cert_payload_create_from_cert(cert); - } - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) - { - DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); - return cert_payload_create_from_cert(cert); - } - - if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) - { - DBG1(DBG_IKE, "encoding certificate for cert payload failed"); - hasher->destroy(hasher); - return NULL; - } - hasher->allocate_hash(hasher, encoded, &hash); - chunk_free(&encoded); - hasher->destroy(hasher); - id = identification_create_from_encoding(ID_KEY_ID, hash); - - enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); - if (enumerator->enumerate(enumerator, &url)) - { - payload = cert_payload_create_from_hash_and_url(hash, url); - DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); - } - else - { - payload = cert_payload_create_from_cert(cert); - } - enumerator->destroy(enumerator); - chunk_free(&hash); - id->destroy(id); - return payload; -} - -/** - * add certificates to message - */ -static void build_certs(private_ike_cert_post_t *this, message_t *message) -{ - peer_cfg_t *peer_cfg; - auth_payload_t *payload; - - payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK) - { /* no CERT payload for EAP/PSK */ - return; - } - - switch (peer_cfg->get_cert_policy(peer_cfg)) - { - case CERT_NEVER_SEND: - break; - case CERT_SEND_IF_ASKED: - if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) - { - break; - } - /* FALL */ - case CERT_ALWAYS_SEND: - { - cert_payload_t *payload; - enumerator_t *enumerator; - certificate_t *cert; - auth_rule_t type; - auth_cfg_t *auth; - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - - /* get subject cert first, then issuing certificates */ - cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); - if (!cert) - { - break; - } - payload = build_cert_payload(this, cert); - if (!payload) - { - break; - } - DBG1(DBG_IKE, "sending end entity cert \"%Y\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - - enumerator = auth->create_enumerator(auth); - while (enumerator->enumerate(enumerator, &type, &cert)) - { - if (type == AUTH_RULE_IM_CERT) - { - payload = cert_payload_create_from_cert(cert); - if (payload) - { - DBG1(DBG_IKE, "sending issuer cert \"%Y\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - } - } - } - enumerator->destroy(enumerator); - } - } -} - -METHOD(task_t, build_i, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - build_certs(this, message); - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - build_certs(this, message); - - if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { /* stay alive, we might have additional rounds with certs */ - return NEED_MORE; - } - return SUCCESS; -} - -METHOD(task_t, process_i, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { /* stay alive, we might have additional rounds with CERTS */ - return NEED_MORE; - } - return SUCCESS; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_cert_post_t *this) -{ - return IKE_CERT_POST; -} - -METHOD(task_t, migrate, void, - private_ike_cert_post_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; -} - -METHOD(task_t, destroy, void, - private_ike_cert_post_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_cert_post_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .initiator = initiator, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_cert_post.h b/src/libcharon/sa/tasks/ike_cert_post.h deleted file mode 100644 index b3881a01a..000000000 --- a/src/libcharon/sa/tasks/ike_cert_post.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2007-2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_cert_post ike_cert_post - * @{ @ingroup tasks - */ - -#ifndef IKE_CERT_POST_H_ -#define IKE_CERT_POST_H_ - -typedef struct ike_cert_post_t ike_cert_post_t; - -#include -#include -#include - -/** - * Task of type ike_cert_post, certificate processing after authentication. - */ -struct ike_cert_post_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_cert_post task. - * - * The initiator parameter means the original initiator, not the initiator - * of the certificate request. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is the original initiator - * @return ike_cert_post task to handle by the task_manager - */ -ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_CERT_POST_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c deleted file mode 100644 index b33aebe46..000000000 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_cert_pre.h" - -#include -#include -#include -#include -#include - - -typedef struct private_ike_cert_pre_t private_ike_cert_pre_t; - -/** - * Private members of a ike_cert_pre_t task. - */ -struct private_ike_cert_pre_t { - - /** - * Public methods and task_t interface. - */ - ike_cert_pre_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Do we accept HTTP certificate lookup requests - */ - bool do_http_lookup; - - /** - * whether this is the final authentication round - */ - bool final; -}; - -/** - * read certificate requests - */ -static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - auth_cfg_t *auth; - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case CERTIFICATE_REQUEST: - { - certreq_payload_t *certreq = (certreq_payload_t*)payload; - enumerator_t *enumerator; - u_int unknown = 0; - chunk_t keyid; - - this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); - - if (certreq->get_cert_type(certreq) != CERT_X509) - { - DBG1(DBG_IKE, "cert payload %N not supported - ignored", - certificate_type_names, certreq->get_cert_type(certreq)); - break; - } - enumerator = certreq->create_keyid_enumerator(certreq); - while (enumerator->enumerate(enumerator, &keyid)) - { - identification_t *id; - certificate_t *cert; - - id = identification_create_from_encoding(ID_KEY_ID, keyid); - cert = lib->credmgr->get_cert(lib->credmgr, - CERT_X509, KEY_ANY, id, TRUE); - if (cert) - { - DBG1(DBG_IKE, "received cert request for \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_RULE_CA_CERT, cert); - } - else - { - DBG2(DBG_IKE, "received cert request for unknown ca " - "with keyid %Y", id); - unknown++; - } - id->destroy(id); - } - enumerator->destroy(enumerator); - if (unknown) - { - DBG1(DBG_IKE, "received %u cert requests for an unknown ca", - unknown); - } - break; - } - case NOTIFY: - { - notify_payload_t *notify = (notify_payload_t*)payload; - - /* we only handle one type of notify here */ - if (notify->get_notify_type(notify) == HTTP_CERT_LOOKUP_SUPPORTED) - { - this->ike_sa->enable_extension(this->ike_sa, EXT_HASH_AND_URL); - } - break; - } - default: - /* ignore other payloads here, these are handled elsewhere */ - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * tries to extract a certificate from the cert payload or the credential - * manager (based on the hash of a "Hash and URL" encoded cert). - * Note: the returned certificate (if any) has to be destroyed - */ -static certificate_t *try_get_cert(cert_payload_t *cert_payload) -{ - certificate_t *cert = NULL; - - switch (cert_payload->get_cert_encoding(cert_payload)) - { - case ENC_X509_SIGNATURE: - { - cert = cert_payload->get_cert(cert_payload); - break; - } - case ENC_X509_HASH_AND_URL: - { - identification_t *id; - chunk_t hash = cert_payload->get_hash(cert_payload); - if (!hash.ptr) - { - /* invalid "Hash and URL" data (logged elsewhere) */ - break; - } - id = identification_create_from_encoding(ID_KEY_ID, hash); - cert = lib->credmgr->get_cert(lib->credmgr, - CERT_X509, KEY_ANY, id, FALSE); - id->destroy(id); - break; - } - default: - { - break; - } - } - return cert; -} - -/** - * import certificates - */ -static void process_certs(private_ike_cert_pre_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - auth_cfg_t *auth; - bool first = TRUE; - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == CERTIFICATE) - { - cert_payload_t *cert_payload; - cert_encoding_t encoding; - certificate_t *cert; - char *url; - - cert_payload = (cert_payload_t*)payload; - encoding = cert_payload->get_cert_encoding(cert_payload); - - switch (encoding) - { - case ENC_X509_HASH_AND_URL: - { - if (!this->do_http_lookup) - { - DBG1(DBG_IKE, "received hash-and-url encoded cert, but" - " we don't accept them, ignore"); - break; - } - /* FALL */ - } - case ENC_X509_SIGNATURE: - { - cert = try_get_cert(cert_payload); - if (cert) - { - if (first) - { /* the first is an end entity certificate */ - DBG1(DBG_IKE, "received end entity cert \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); - first = FALSE; - } - else - { - DBG1(DBG_IKE, "received issuer cert \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_HELPER_IM_CERT, cert); - } - } - else if (encoding == ENC_X509_HASH_AND_URL) - { - /* we fetch the certificate not yet, but only if - * it is really needed during authentication */ - url = cert_payload->get_url(cert_payload); - if (!url) - { - DBG1(DBG_IKE, "received invalid hash-and-url " - "encoded cert, ignore"); - break; - } - url = strdup(url); - if (first) - { /* first URL is for an end entity certificate */ - DBG1(DBG_IKE, "received hash-and-url for end" - " entity cert \"%s\"", url); - auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url); - first = FALSE; - } - else - { - DBG1(DBG_IKE, "received hash-and-url for issuer" - " cert \"%s\"", url); - auth->add(auth, AUTH_HELPER_IM_HASH_URL, url); - } - } - break; - } - case ENC_CRL: - cert = cert_payload->get_cert(cert_payload); - if (cert) - { - DBG1(DBG_IKE, "received CRL \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert); - } - break; - case ENC_PKCS7_WRAPPED_X509: - case ENC_PGP: - case ENC_DNS_SIGNED_KEY: - case ENC_KERBEROS_TOKEN: - case ENC_ARL: - case ENC_SPKI: - case ENC_X509_ATTRIBUTE: - case ENC_RAW_RSA_KEY: - case ENC_X509_HASH_AND_URL_BUNDLE: - case ENC_OCSP_CONTENT: - default: - DBG1(DBG_ENC, "certificate encoding %N not supported", - cert_encoding_names, encoding); - } - } - } - enumerator->destroy(enumerator); -} - -/** - * add the keyid of a certificate to the certificate request payload - */ -static void add_certreq(certreq_payload_t **req, certificate_t *cert) -{ - switch (cert->get_type(cert)) - { - case CERT_X509: - { - public_key_t *public; - chunk_t keyid; - x509_t *x509 = (x509_t*)cert; - - if (!(x509->get_flags(x509) & X509_CA)) - { /* no CA cert, skip */ - break; - } - public = cert->get_public_key(cert); - if (!public) - { - break; - } - if (*req == NULL) - { - *req = certreq_payload_create_type(CERT_X509); - } - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - (*req)->add_keyid(*req, keyid); - DBG1(DBG_IKE, "sending cert request for \"%Y\"", - cert->get_subject(cert)); - } - public->destroy(public); - break; - } - default: - break; - } -} - -/** - * add a auth_cfg's CA certificates to the certificate request - */ -static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) -{ - enumerator_t *enumerator; - auth_rule_t type; - void *value; - - enumerator = auth->create_enumerator(auth); - while (enumerator->enumerate(enumerator, &type, &value)) - { - switch (type) - { - case AUTH_RULE_CA_CERT: - add_certreq(req, (certificate_t*)value); - break; - default: - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * build certificate requests - */ -static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) -{ - enumerator_t *enumerator; - ike_cfg_t *ike_cfg; - peer_cfg_t *peer_cfg; - certificate_t *cert; - auth_cfg_t *auth; - certreq_payload_t *req = NULL; - - ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - if (!ike_cfg->send_certreq(ike_cfg)) - { - return; - } - - /* check if we require a specific CA for that peer */ - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg) - { - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); - while (enumerator->enumerate(enumerator, &auth)) - { - add_certreqs(&req, auth); - } - enumerator->destroy(enumerator); - } - - if (!req) - { - /* otherwise add all trusted CA certificates */ - enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, - CERT_ANY, KEY_ANY, NULL, TRUE); - while (enumerator->enumerate(enumerator, &cert)) - { - add_certreq(&req, cert); - } - enumerator->destroy(enumerator); - } - - if (req) - { - message->add_payload(message, (payload_t*)req); - - if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE)) - { - message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, - chunk_empty); - this->do_http_lookup = TRUE; - } - } -} - -/** - * Check if this is the final authentication round - */ -static bool final_auth(message_t *message) -{ - /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */ - if (message->get_payload(message, AUTHENTICATION) == NULL) - { - return FALSE; - } - if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS)) - { - return FALSE; - } - return TRUE; -} - -METHOD(task_t, build_i, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_message_id(message) == 1) - { /* initiator sends CERTREQs in first IKE_AUTH */ - build_certreqs(this, message); - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_exchange_type(message) != IKE_SA_INIT) - { /* handle certreqs/certs in any IKE_AUTH, just in case */ - process_certreqs(this, message); - process_certs(this, message); - } - this->final = final_auth(message); - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - build_certreqs(this, message); - } - if (this->final) - { - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - process_certreqs(this, message); - } - process_certs(this, message); - - if (final_auth(message)) - { - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_cert_pre_t *this) -{ - return IKE_CERT_PRE; -} - -METHOD(task_t, migrate, void, - private_ike_cert_pre_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; -} - -METHOD(task_t, destroy, void, - private_ike_cert_pre_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_cert_pre_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .initiator = initiator, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_cert_pre.h b/src/libcharon/sa/tasks/ike_cert_pre.h deleted file mode 100644 index 4b2d0d470..000000000 --- a/src/libcharon/sa/tasks/ike_cert_pre.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2007-2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_cert_pre ike_cert_pre - * @{ @ingroup tasks - */ - -#ifndef IKE_CERT_PRE_H_ -#define IKE_CERT_PRE_H_ - -typedef struct ike_cert_pre_t ike_cert_pre_t; - -#include -#include -#include - -/** - * Task of type ike_cert_post, certificate processing before authentication. - */ -struct ike_cert_pre_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_cert_pre task. - * - * The initiator parameter means the original initiator, not the initiator - * of the certificate request. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is the original initiator - * @return ike_cert_pre task to handle by the task_manager - */ -ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_CERT_PRE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_config.c b/src/libcharon/sa/tasks/ike_config.c deleted file mode 100644 index 4ef9c56a5..000000000 --- a/src/libcharon/sa/tasks/ike_config.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_config.h" - -#include -#include -#include - -typedef struct private_ike_config_t private_ike_config_t; - -/** - * Private members of a ike_config_t task. - */ -struct private_ike_config_t { - - /** - * Public methods and task_t interface. - */ - ike_config_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * virtual ip - */ - host_t *virtual_ip; - - /** - * list of attributes requested and its handler, entry_t - */ - linked_list_t *requested; -}; - -/** - * Entry for a requested attribute and the requesting handler - */ -typedef struct { - /** attribute requested */ - configuration_attribute_type_t type; - /** handler requesting this attribute */ - attribute_handler_t *handler; -} entry_t; - -/** - * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip - */ -static configuration_attribute_t *build_vip(host_t *vip) -{ - configuration_attribute_type_t type; - chunk_t chunk, prefix; - - if (vip->get_family(vip) == AF_INET) - { - type = INTERNAL_IP4_ADDRESS; - if (vip->is_anyaddr(vip)) - { - chunk = chunk_empty; - } - else - { - chunk = vip->get_address(vip); - } - } - else - { - type = INTERNAL_IP6_ADDRESS; - if (vip->is_anyaddr(vip)) - { - chunk = chunk_empty; - } - else - { - prefix = chunk_alloca(1); - *prefix.ptr = 64; - chunk = vip->get_address(vip); - chunk = chunk_cata("cc", chunk, prefix); - } - } - return configuration_attribute_create_value(type, chunk); -} - -/** - * Handle a received attribute as initiator - */ -static void handle_attribute(private_ike_config_t *this, - configuration_attribute_t *ca) -{ - attribute_handler_t *handler = NULL; - enumerator_t *enumerator; - entry_t *entry; - - /* find the handler which requested this attribute */ - enumerator = this->requested->create_enumerator(this->requested); - while (enumerator->enumerate(enumerator, &entry)) - { - if (entry->type == ca->get_type(ca)) - { - handler = entry->handler; - this->requested->remove_at(this->requested, enumerator); - free(entry); - break; - } - } - enumerator->destroy(enumerator); - - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - this->ike_sa->get_other_id(this->ike_sa), handler, - ca->get_type(ca), ca->get_value(ca)); - if (handler) - { - this->ike_sa->add_configuration_attribute(this->ike_sa, - handler, ca->get_type(ca), ca->get_value(ca)); - } -} - -/** - * process a single configuration attribute - */ -static void process_attribute(private_ike_config_t *this, - configuration_attribute_t *ca) -{ - host_t *ip; - chunk_t addr; - int family = AF_INET6; - - switch (ca->get_type(ca)) - { - case INTERNAL_IP4_ADDRESS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_ADDRESS: - { - addr = ca->get_value(ca); - if (addr.len == 0) - { - ip = host_create_any(family); - } - else - { - /* skip prefix byte in IPv6 payload*/ - if (family == AF_INET6) - { - addr.len--; - } - ip = host_create_from_chunk(family, addr, 0); - } - if (ip) - { - DESTROY_IF(this->virtual_ip); - this->virtual_ip = ip; - } - break; - } - case INTERNAL_IP4_SERVER: - case INTERNAL_IP6_SERVER: - /* assume it's a Windows client if we see proprietary attributes */ - this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS); - /* fall */ - default: - { - if (this->initiator) - { - handle_attribute(this, ca); - } - } - } -} - -/** - * Scan for configuration payloads and attributes - */ -static void process_payloads(private_ike_config_t *this, message_t *message) -{ - enumerator_t *enumerator, *attributes; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == CONFIGURATION) - { - cp_payload_t *cp = (cp_payload_t*)payload; - configuration_attribute_t *ca; - - switch (cp->get_type(cp)) - { - case CFG_REQUEST: - case CFG_REPLY: - { - attributes = cp->create_attribute_enumerator(cp); - while (attributes->enumerate(attributes, &ca)) - { - DBG2(DBG_IKE, "processing %N attribute", - configuration_attribute_type_names, ca->get_type(ca)); - process_attribute(this, ca); - } - attributes->destroy(attributes); - break; - } - default: - DBG1(DBG_IKE, "ignoring %N config payload", - config_type_names, cp->get_type(cp)); - break; - } - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_ike_config_t *this, message_t *message) -{ - if (message->get_message_id(message) == 1) - { /* in first IKE_AUTH only */ - cp_payload_t *cp = NULL; - enumerator_t *enumerator; - attribute_handler_t *handler; - peer_cfg_t *config; - configuration_attribute_type_t type; - chunk_t data; - host_t *vip; - - /* reuse virtual IP if we already have one */ - vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (!vip) - { - config = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = config->get_virtual_ip(config); - } - if (vip) - { - cp = cp_payload_create_type(CFG_REQUEST); - cp->add_attribute(cp, build_vip(vip)); - } - - enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes, - this->ike_sa->get_other_id(this->ike_sa), vip); - while (enumerator->enumerate(enumerator, &handler, &type, &data)) - { - configuration_attribute_t *ca; - entry_t *entry; - - /* create configuration attribute */ - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); - ca = configuration_attribute_create_value(type, data); - if (!cp) - { - cp = cp_payload_create_type(CFG_REQUEST); - } - cp->add_attribute(cp, ca); - - /* save handler along with requested type */ - entry = malloc_thing(entry_t); - entry->type = type; - entry->handler = handler; - - this->requested->insert_last(this->requested, entry); - } - enumerator->destroy(enumerator); - - if (cp) - { - message->add_payload(message, (payload_t*)cp); - } - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_config_t *this, message_t *message) -{ - if (message->get_message_id(message) == 1) - { /* in first IKE_AUTH only */ - process_payloads(this, message); - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_config_t *this, message_t *message) -{ - if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { /* in last IKE_AUTH exchange */ - enumerator_t *enumerator; - configuration_attribute_type_t type; - chunk_t value; - host_t *vip = NULL; - cp_payload_t *cp = NULL; - peer_cfg_t *config; - identification_t *id; - - id = this->ike_sa->get_other_eap_id(this->ike_sa); - - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (this->virtual_ip) - { - DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); - if (config->get_pool(config)) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - config->get_pool(config), id, this->virtual_ip); - } - if (vip == NULL) - { - DBG1(DBG_IKE, "no virtual IP found, sending %N", - notify_type_names, INTERNAL_ADDRESS_FAILURE); - message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE, - chunk_empty); - return SUCCESS; - } - DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); - this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); - - cp = cp_payload_create_type(CFG_REPLY); - cp->add_attribute(cp, build_vip(vip)); - } - - /* query registered providers for additional attributes to include */ - enumerator = hydra->attributes->create_responder_enumerator( - hydra->attributes, config->get_pool(config), id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - if (!cp) - { - cp = cp_payload_create_type(CFG_REPLY); - } - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); - cp->add_attribute(cp, - configuration_attribute_create_value(type, value)); - } - enumerator->destroy(enumerator); - - if (cp) - { - message->add_payload(message, (payload_t*)cp); - } - DESTROY_IF(vip); - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_config_t *this, message_t *message) -{ - if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { /* in last IKE_AUTH exchange */ - - process_payloads(this, message); - - if (this->virtual_ip) - { - this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); - } - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_config_t *this) -{ - return IKE_CONFIG; -} - -METHOD(task_t, migrate, void, - private_ike_config_t *this, ike_sa_t *ike_sa) -{ - DESTROY_IF(this->virtual_ip); - - this->ike_sa = ike_sa; - this->virtual_ip = NULL; - this->requested->destroy_function(this->requested, free); - this->requested = linked_list_create(); -} - -METHOD(task_t, destroy, void, - private_ike_config_t *this) -{ - DESTROY_IF(this->virtual_ip); - this->requested->destroy_function(this->requested, free); - free(this); -} - -/* - * Described in header. - */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_config_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .initiator = initiator, - .ike_sa = ike_sa, - .requested = linked_list_create(), - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_config.h b/src/libcharon/sa/tasks/ike_config.h deleted file mode 100644 index 8cef08697..000000000 --- a/src/libcharon/sa/tasks/ike_config.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_config ike_config - * @{ @ingroup tasks - */ - -#ifndef IKE_CONFIG_H_ -#define IKE_CONFIG_H_ - -typedef struct ike_config_t ike_config_t; - -#include -#include -#include - -/** - * Task of type IKE_CONFIG, sets up a virtual IP and other - * configurations for an IKE_SA. - */ -struct ike_config_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_config task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE for initiator - * @return ike_config task to handle by the task_manager - */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_CONFIG_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c deleted file mode 100644 index d79674fe4..000000000 --- a/src/libcharon/sa/tasks/ike_delete.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2006-2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_delete.h" - -#include -#include - - -typedef struct private_ike_delete_t private_ike_delete_t; - -/** - * Private members of a ike_delete_t task. - */ -struct private_ike_delete_t { - - /** - * Public methods and task_t interface. - */ - ike_delete_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * are we deleting a rekeyed SA? - */ - bool rekeyed; - - /** - * are we responding to a delete, but have initated our own? - */ - bool simultaneous; -}; - -METHOD(task_t, build_i, status_t, - private_ike_delete_t *this, message_t *message) -{ - delete_payload_t *delete_payload; - - DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - delete_payload = delete_payload_create(PROTO_IKE); - message->add_payload(message, (payload_t*)delete_payload); - - if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) - { - this->rekeyed = TRUE; - } - this->ike_sa->set_state(this->ike_sa, IKE_DELETING); - - DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa)); - - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_delete_t *this, message_t *message) -{ - DBG0(DBG_IKE, "IKE_SA deleted"); - if (!this->rekeyed) - { /* invoke ike_down() hook if SA has not been rekeyed */ - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - /* completed, delete IKE_SA by returning DESTROY_ME */ - return DESTROY_ME; -} - -METHOD(task_t, process_r, status_t, - private_ike_delete_t *this, message_t *message) -{ - /* we don't even scan the payloads, as the message wouldn't have - * come so far without being correct */ - DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa)); - DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - switch (this->ike_sa->get_state(this->ike_sa)) - { - case IKE_ESTABLISHED: - this->ike_sa->set_state(this->ike_sa, IKE_DELETING); - this->ike_sa->reestablish(this->ike_sa); - return NEED_MORE; - case IKE_REKEYING: - this->rekeyed = TRUE; - break; - case IKE_DELETING: - this->simultaneous = TRUE; - break; - default: - break; - } - this->ike_sa->set_state(this->ike_sa, IKE_DELETING); - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_delete_t *this, message_t *message) -{ - DBG0(DBG_IKE, "IKE_SA deleted"); - - if (this->simultaneous) - { - /* wait for peer's response for our delete request */ - return SUCCESS; - } - if (!this->rekeyed) - { /* invoke ike_down() hook if SA has not been rekeyed */ - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - /* completed, delete IKE_SA by returning DESTROY_ME */ - return DESTROY_ME; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_delete_t *this) -{ - return IKE_DELETE; -} - -METHOD(task_t, migrate, void, - private_ike_delete_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; - this->simultaneous = FALSE; -} - -METHOD(task_t, destroy, void, - private_ike_delete_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_delete_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .initiator = initiator, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_delete.h b/src/libcharon/sa/tasks/ike_delete.h deleted file mode 100644 index 82782f393..000000000 --- a/src/libcharon/sa/tasks/ike_delete.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_delete ike_delete - * @{ @ingroup tasks - */ - -#ifndef IKE_DELETE_H_ -#define IKE_DELETE_H_ - -typedef struct ike_delete_t ike_delete_t; - -#include -#include -#include - -/** - * Task of type ike_delete, delete an IKE_SA. - */ -struct ike_delete_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_delete task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if we initiate the delete - * @return ike_delete task to handle by the task_manager - */ -ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_dpd.c b/src/libcharon/sa/tasks/ike_dpd.c deleted file mode 100644 index 106eff87c..000000000 --- a/src/libcharon/sa/tasks/ike_dpd.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_dpd.h" - -#include - - -typedef struct private_ike_dpd_t private_ike_dpd_t; - -/** - * Private members of a ike_dpd_t task. - */ -struct private_ike_dpd_t { - - /** - * Public methods and task_t interface. - */ - ike_dpd_t public; -}; - -METHOD(task_t, return_need_more, status_t, - private_ike_dpd_t *this, message_t *message) -{ - return NEED_MORE; -} - -METHOD(task_t, return_success, status_t, - private_ike_dpd_t *this, message_t *message) -{ - return SUCCESS; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_dpd_t *this) -{ - return IKE_DPD; -} - - -METHOD(task_t, migrate, void, - private_ike_dpd_t *this, ike_sa_t *ike_sa) -{ - -} - -METHOD(task_t, destroy, void, - private_ike_dpd_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -ike_dpd_t *ike_dpd_create(bool initiator) -{ - private_ike_dpd_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - }, - ); - - if (initiator) - { - this->public.task.build = _return_need_more; - this->public.task.process = _return_success; - } - else - { - this->public.task.build = _return_success; - this->public.task.process = _return_need_more; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_dpd.h b/src/libcharon/sa/tasks/ike_dpd.h deleted file mode 100644 index a9f68c31c..000000000 --- a/src/libcharon/sa/tasks/ike_dpd.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_dpd ike_dpd - * @{ @ingroup tasks - */ - -#ifndef IKE_DPD_H_ -#define IKE_DPD_H_ - -typedef struct ike_dpd_t ike_dpd_t; - -#include -#include -#include - -/** - * Task of type ike_dpd, detects dead peers. - * - * The DPD task actually does nothing, as a DPD has no associated payloads. - */ -struct ike_dpd_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_dpd task. - * - * @param initiator TRUE if task is the original initiator - * @return ike_dpd task to handle by the task_manager - */ -ike_dpd_t *ike_dpd_create(bool initiator); - -#endif /** IKE_DPD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c deleted file mode 100644 index dd8a4b086..000000000 --- a/src/libcharon/sa/tasks/ike_init.c +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (C) 2008-2009 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_init.h" - -#include - -#include -#include -#include -#include -#include - -/** maximum retries to do with cookies/other dh groups */ -#define MAX_RETRIES 5 - -typedef struct private_ike_init_t private_ike_init_t; - -/** - * Private members of a ike_init_t task. - */ -struct private_ike_init_t { - - /** - * Public methods and task_t interface. - */ - ike_init_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * IKE config to establish - */ - ike_cfg_t *config; - - /** - * diffie hellman group to use - */ - diffie_hellman_group_t dh_group; - - /** - * diffie hellman key exchange - */ - diffie_hellman_t *dh; - - /** - * Keymat derivation (from IKE_SA) - */ - keymat_t *keymat; - - /** - * nonce chosen by us - */ - chunk_t my_nonce; - - /** - * nonce chosen by peer - */ - chunk_t other_nonce; - - /** - * Negotiated proposal used for IKE_SA - */ - proposal_t *proposal; - - /** - * Old IKE_SA which gets rekeyed - */ - ike_sa_t *old_sa; - - /** - * cookie received from responder - */ - chunk_t cookie; - - /** - * retries done so far after failure (cookie or bad dh group) - */ - u_int retry; -}; - -/** - * build the payloads for the message - */ -static void build_payloads(private_ike_init_t *this, message_t *message) -{ - sa_payload_t *sa_payload; - ke_payload_t *ke_payload; - nonce_payload_t *nonce_payload; - linked_list_t *proposal_list; - ike_sa_id_t *id; - proposal_t *proposal; - enumerator_t *enumerator; - - id = this->ike_sa->get_id(this->ike_sa); - - this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - - if (this->initiator) - { - proposal_list = this->config->get_proposals(this->config); - if (this->old_sa) - { - /* include SPI of new IKE_SA when we are rekeying */ - enumerator = proposal_list->create_enumerator(proposal_list); - while (enumerator->enumerate(enumerator, (void**)&proposal)) - { - proposal->set_spi(proposal, id->get_initiator_spi(id)); - } - enumerator->destroy(enumerator); - } - - sa_payload = sa_payload_create_from_proposal_list(proposal_list); - proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); - } - else - { - if (this->old_sa) - { - /* include SPI of new IKE_SA when we are rekeying */ - this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); - } - sa_payload = sa_payload_create_from_proposal(this->proposal); - } - message->add_payload(message, (payload_t*)sa_payload); - - nonce_payload = nonce_payload_create(); - nonce_payload->set_nonce(nonce_payload, this->my_nonce); - ke_payload = ke_payload_create_from_diffie_hellman(this->dh); - - if (this->old_sa) - { /* payload order differs if we are rekeying */ - message->add_payload(message, (payload_t*)nonce_payload); - message->add_payload(message, (payload_t*)ke_payload); - } - else - { - message->add_payload(message, (payload_t*)ke_payload); - message->add_payload(message, (payload_t*)nonce_payload); - } -} - -/** - * Read payloads from message - */ -static void process_payloads(private_ike_init_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case SECURITY_ASSOCIATION: - { - sa_payload_t *sa_payload = (sa_payload_t*)payload; - linked_list_t *proposal_list; - bool private; - - proposal_list = sa_payload->get_proposals(sa_payload); - private = this->ike_sa->supports_extension(this->ike_sa, - EXT_STRONGSWAN); - this->proposal = this->config->select_proposal(this->config, - proposal_list, private); - proposal_list->destroy_offset(proposal_list, - offsetof(proposal_t, destroy)); - break; - } - case KEY_EXCHANGE: - { - ke_payload_t *ke_payload = (ke_payload_t*)payload; - - this->dh_group = ke_payload->get_dh_group_number(ke_payload); - if (!this->initiator) - { - this->dh = this->keymat->create_dh(this->keymat, - this->dh_group); - } - if (this->dh) - { - this->dh->set_other_public_value(this->dh, - ke_payload->get_key_exchange_data(ke_payload)); - } - break; - } - case NONCE: - { - nonce_payload_t *nonce_payload = (nonce_payload_t*)payload; - - this->other_nonce = nonce_payload->get_nonce(nonce_payload); - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_ike_init_t *this, message_t *message) -{ - rng_t *rng; - - this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); - - if (this->retry >= MAX_RETRIES) - { - DBG1(DBG_IKE, "giving up after %d retries", MAX_RETRIES); - return FAILED; - } - - /* if the DH group is set via use_dh_group(), we already have a DH object */ - if (!this->dh) - { - this->dh_group = this->config->get_dh_group(this->config); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); - if (!this->dh) - { - DBG1(DBG_IKE, "configured DH group %N not supported", - diffie_hellman_group_names, this->dh_group); - return FAILED; - } - } - - /* generate nonce only when we are trying the first time */ - if (this->my_nonce.ptr == NULL) - { - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_IKE, "error generating nonce"); - return FAILED; - } - rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce); - rng->destroy(rng); - } - - if (this->cookie.ptr) - { - message->add_notify(message, FALSE, COOKIE, this->cookie); - } - - build_payloads(this, message); - -#ifdef ME - { - chunk_t connect_id = this->ike_sa->get_connect_id(this->ike_sa); - if (connect_id.ptr) - { - message->add_notify(message, FALSE, ME_CONNECTID, connect_id); - } - } -#endif /* ME */ - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_init_t *this, message_t *message) -{ - rng_t *rng; - - this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - DBG0(DBG_IKE, "%H is initiating an IKE_SA", message->get_source(message)); - this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_IKE, "error generating nonce"); - return FAILED; - } - rng->allocate_bytes(rng, NONCE_SIZE, &this->my_nonce); - rng->destroy(rng); - -#ifdef ME - { - notify_payload_t *notify = message->get_notify(message, ME_CONNECTID); - if (notify) - { - chunk_t connect_id = notify->get_notification_data(notify); - DBG2(DBG_IKE, "received ME_CONNECTID %#B", &connect_id); - charon->connect_manager->stop_checks(charon->connect_manager, - connect_id); - } - } -#endif /* ME */ - - process_payloads(this, message); - - return NEED_MORE; -} - -/** - * Derive the keymat for the IKE_SA - */ -static bool derive_keys(private_ike_init_t *this, - chunk_t nonce_i, chunk_t nonce_r) -{ - keymat_t *old_keymat; - pseudo_random_function_t prf_alg = PRF_UNDEFINED; - chunk_t skd = chunk_empty; - ike_sa_id_t *id; - - id = this->ike_sa->get_id(this->ike_sa); - if (this->old_sa) - { - /* rekeying: Include old SKd, use old PRF, apply SPI */ - old_keymat = this->old_sa->get_keymat(this->old_sa); - prf_alg = old_keymat->get_skd(old_keymat, &skd); - if (this->initiator) - { - id->set_responder_spi(id, this->proposal->get_spi(this->proposal)); - } - else - { - id->set_initiator_spi(id, this->proposal->get_spi(this->proposal)); - } - } - if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, - nonce_i, nonce_r, id, prf_alg, skd)) - { - return FALSE; - } - charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, - nonce_i, nonce_r, this->old_sa); - return TRUE; -} - -METHOD(task_t, build_r, status_t, - private_ike_init_t *this, message_t *message) -{ - /* check if we have everything we need */ - if (this->proposal == NULL || - this->other_nonce.len == 0 || this->my_nonce.len == 0) - { - DBG1(DBG_IKE, "received proposals inacceptable"); - message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); - return FAILED; - } - this->ike_sa->set_proposal(this->ike_sa, this->proposal); - - if (this->dh == NULL || - !this->proposal->has_dh_group(this->proposal, this->dh_group)) - { - u_int16_t group; - - if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, - &group, NULL)) - { - DBG1(DBG_IKE, "DH group %N inacceptable, requesting %N", - diffie_hellman_group_names, this->dh_group, - diffie_hellman_group_names, group); - this->dh_group = group; - group = htons(group); - message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, - chunk_from_thing(group)); - } - else - { - DBG1(DBG_IKE, "no acceptable proposal found"); - } - return FAILED; - } - - if (!derive_keys(this, this->other_nonce, this->my_nonce)) - { - DBG1(DBG_IKE, "key derivation failed"); - message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); - return FAILED; - } - build_payloads(this, message); - return SUCCESS; -} - -METHOD(task_t, process_i, status_t, - private_ike_init_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - - /* check for erronous notifies */ - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == NOTIFY) - { - notify_payload_t *notify = (notify_payload_t*)payload; - notify_type_t type = notify->get_notify_type(notify); - - switch (type) - { - case INVALID_KE_PAYLOAD: - { - chunk_t data; - diffie_hellman_group_t bad_group; - - bad_group = this->dh_group; - data = notify->get_notification_data(notify); - this->dh_group = ntohs(*((u_int16_t*)data.ptr)); - DBG1(DBG_IKE, "peer didn't accept DH group %N, " - "it requested %N", diffie_hellman_group_names, - bad_group, diffie_hellman_group_names, this->dh_group); - - if (this->old_sa == NULL) - { /* reset the IKE_SA if we are not rekeying */ - this->ike_sa->reset(this->ike_sa); - } - - enumerator->destroy(enumerator); - this->retry++; - return NEED_MORE; - } - case NAT_DETECTION_SOURCE_IP: - case NAT_DETECTION_DESTINATION_IP: - /* skip, handled in ike_natd_t */ - break; - case MULTIPLE_AUTH_SUPPORTED: - /* handled in ike_auth_t */ - break; - case COOKIE: - { - chunk_free(&this->cookie); - this->cookie = chunk_clone(notify->get_notification_data(notify)); - this->ike_sa->reset(this->ike_sa); - enumerator->destroy(enumerator); - DBG2(DBG_IKE, "received %N notify", notify_type_names, type); - this->retry++; - return NEED_MORE; - } - default: - { - if (type <= 16383) - { - DBG1(DBG_IKE, "received %N notify error", - notify_type_names, type); - enumerator->destroy(enumerator); - return FAILED; - } - DBG2(DBG_IKE, "received %N notify", - notify_type_names, type); - break; - } - } - } - } - enumerator->destroy(enumerator); - - process_payloads(this, message); - - /* check if we have everything */ - if (this->proposal == NULL || - this->other_nonce.len == 0 || this->my_nonce.len == 0) - { - DBG1(DBG_IKE, "peers proposal selection invalid"); - return FAILED; - } - this->ike_sa->set_proposal(this->ike_sa, this->proposal); - - if (this->dh == NULL || - !this->proposal->has_dh_group(this->proposal, this->dh_group)) - { - DBG1(DBG_IKE, "peer DH group selection invalid"); - return FAILED; - } - - if (!derive_keys(this, this->my_nonce, this->other_nonce)) - { - DBG1(DBG_IKE, "key derivation failed"); - return FAILED; - } - return SUCCESS; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_init_t *this) -{ - return IKE_INIT; -} - -METHOD(task_t, migrate, void, - private_ike_init_t *this, ike_sa_t *ike_sa) -{ - DESTROY_IF(this->proposal); - chunk_free(&this->other_nonce); - - this->ike_sa = ike_sa; - this->keymat = ike_sa->get_keymat(ike_sa); - this->proposal = NULL; - if (this->dh && this->dh->get_dh_group(this->dh) != this->dh_group) - { /* reset DH value only if group changed (INVALID_KE_PAYLOAD) */ - this->dh->destroy(this->dh); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); - } -} - -METHOD(task_t, destroy, void, - private_ike_init_t *this) -{ - DESTROY_IF(this->dh); - DESTROY_IF(this->proposal); - chunk_free(&this->my_nonce); - chunk_free(&this->other_nonce); - chunk_free(&this->cookie); - free(this); -} - -METHOD(ike_init_t, get_lower_nonce, chunk_t, - private_ike_init_t *this) -{ - if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, - min(this->my_nonce.len, this->other_nonce.len)) < 0) - { - return this->my_nonce; - } - else - { - return this->other_nonce; - } -} - -/* - * Described in header. - */ -ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) -{ - private_ike_init_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .get_lower_nonce = _get_lower_nonce, - }, - .ike_sa = ike_sa, - .initiator = initiator, - .dh_group = MODP_NONE, - .keymat = ike_sa->get_keymat(ike_sa), - .old_sa = old_sa, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_init.h b/src/libcharon/sa/tasks/ike_init.h deleted file mode 100644 index 4b7f60416..000000000 --- a/src/libcharon/sa/tasks/ike_init.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_init ike_init - * @{ @ingroup tasks - */ - -#ifndef IKE_INIT_H_ -#define IKE_INIT_H_ - -typedef struct ike_init_t ike_init_t; - -#include -#include -#include - -/** - * Task of type IKE_INIT, creates an IKE_SA without authentication. - * - * The authentication of is handle in the ike_auth task. - */ -struct ike_init_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Get the lower of the two nonces, used for rekey collisions. - * - * @return lower nonce - */ - chunk_t (*get_lower_nonce) (ike_init_t *this); -}; - -/** - * Create a new IKE_INIT task. - * - * @param ike_sa IKE_SA this task works for (new one when rekeying) - * @param initiator TRUE if task is the original initiator - * @param old_sa old IKE_SA when we are rekeying - * @return ike_init task to handle by the task_manager - */ -ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa); - -#endif /** IKE_INIT_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_me.c b/src/libcharon/sa/tasks/ike_me.c deleted file mode 100644 index 8f90efcc3..000000000 --- a/src/libcharon/sa/tasks/ike_me.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Copyright (C) 2007-2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_me.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define ME_CONNECTID_LEN 4 -#define ME_CONNECTKEY_LEN 16 - -typedef struct private_ike_me_t private_ike_me_t; - -/** - * Private members of a ike_me_t task. - */ -struct private_ike_me_t { - - /** - * Public methods and task_t interface. - */ - ike_me_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Is this a mediation connection? - */ - bool mediation; - - /** - * Is this the response from another peer? - */ - bool response; - - /** - * Gathered endpoints - */ - linked_list_t *local_endpoints; - - /** - * Parsed endpoints - */ - linked_list_t *remote_endpoints; - - /** - * Did the peer request a callback? - */ - bool callback; - - /** - * Did the connect fail? - */ - bool failed; - - /** - * Was there anything wrong with the payloads? - */ - bool invalid_syntax; - - /** - * The requested peer - */ - identification_t *peer_id; - /** - * Received ID used for connectivity checks - */ - chunk_t connect_id; - - /** - * Received key used for connectivity checks - */ - chunk_t connect_key; - - /** - * Peer config of the mediated connection - */ - peer_cfg_t *mediated_cfg; - -}; - -/** - * Adds a list of endpoints as notifies to a given message - */ -static void add_endpoints_to_message(message_t *message, linked_list_t *endpoints) -{ - enumerator_t *enumerator; - endpoint_notify_t *endpoint; - - enumerator = endpoints->create_enumerator(endpoints); - while (enumerator->enumerate(enumerator, (void**)&endpoint)) - { - message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); - } - enumerator->destroy(enumerator); -} - -/** - * Gathers endpoints and adds them to the current message - */ -static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) -{ - enumerator_t *enumerator; - host_t *addr, *host; - u_int16_t port; - - /* get the port that is used to communicate with the ms */ - host = this->ike_sa->get_my_host(this->ike_sa); - port = host->get_port(host); - - enumerator = hydra->kernel_interface->create_address_enumerator( - hydra->kernel_interface, FALSE, FALSE); - while (enumerator->enumerate(enumerator, (void**)&addr)) - { - host = addr->clone(addr); - host->set_port(host, port); - - this->local_endpoints->insert_last(this->local_endpoints, - endpoint_notify_create_from_host(HOST, host, NULL)); - - host->destroy(host); - } - enumerator->destroy(enumerator); - - host = this->ike_sa->get_server_reflexive_host(this->ike_sa); - if (host) - { - this->local_endpoints->insert_last(this->local_endpoints, - endpoint_notify_create_from_host(SERVER_REFLEXIVE, host, - this->ike_sa->get_my_host(this->ike_sa))); - } - - add_endpoints_to_message(message, this->local_endpoints); -} - -/** - * read notifys from message and evaluate them - */ -static void process_payloads(private_ike_me_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) != NOTIFY) - { - continue; - } - - notify_payload_t *notify = (notify_payload_t*)payload; - - switch (notify->get_notify_type(notify)) - { - case ME_CONNECT_FAILED: - { - DBG2(DBG_IKE, "received ME_CONNECT_FAILED notify"); - this->failed = TRUE; - break; - } - case ME_MEDIATION: - { - DBG2(DBG_IKE, "received ME_MEDIATION notify"); - this->mediation = TRUE; - break; - } - case ME_ENDPOINT: - { - endpoint_notify_t *endpoint; - endpoint = endpoint_notify_create_from_payload(notify); - if (!endpoint) - { - DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify"); - break; - } - DBG1(DBG_IKE, "received %N ME_ENDPOINT %#H", - me_endpoint_type_names, endpoint->get_type(endpoint), - endpoint->get_host(endpoint)); - - this->remote_endpoints->insert_last(this->remote_endpoints, - endpoint); - break; - } - case ME_CALLBACK: - { - DBG2(DBG_IKE, "received ME_CALLBACK notify"); - this->callback = TRUE; - break; - } - case ME_CONNECTID: - { - chunk_free(&this->connect_id); - this->connect_id = chunk_clone(notify->get_notification_data(notify)); - DBG2(DBG_IKE, "received ME_CONNECTID %#B", &this->connect_id); - break; - } - case ME_CONNECTKEY: - { - chunk_free(&this->connect_key); - this->connect_key = chunk_clone(notify->get_notification_data(notify)); - DBG4(DBG_IKE, "received ME_CONNECTKEY %#B", &this->connect_key); - break; - } - case ME_RESPONSE: - { - DBG2(DBG_IKE, "received ME_RESPONSE notify"); - this->response = TRUE; - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case IKE_SA_INIT: - { - peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg->is_mediation(peer_cfg)) - { - DBG2(DBG_IKE, "adding ME_MEDIATION"); - message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty); - } - else - { - return SUCCESS; - } - break; - } - case IKE_AUTH: - { - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) - { - endpoint_notify_t *endpoint; - endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE, - NULL, NULL); - message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); - endpoint->destroy(endpoint); - } - break; - } - case ME_CONNECT: - { - rng_t *rng; - id_payload_t *id_payload; - id_payload = id_payload_create_from_identification(ID_PEER, - this->peer_id); - message->add_payload(message, (payload_t*)id_payload); - - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (!rng) - { - DBG1(DBG_IKE, "unable to generate connect ID for ME_CONNECT"); - return FAILED; - } - if (!this->response) - { - /* only the initiator creates a connect ID. the responder - * returns the connect ID that it received from the initiator */ - rng->allocate_bytes(rng, ME_CONNECTID_LEN, &this->connect_id); - } - rng->allocate_bytes(rng, ME_CONNECTKEY_LEN, &this->connect_key); - rng->destroy(rng); - - message->add_notify(message, FALSE, ME_CONNECTID, this->connect_id); - message->add_notify(message, FALSE, ME_CONNECTKEY, this->connect_key); - - if (this->response) - { - message->add_notify(message, FALSE, ME_RESPONSE, chunk_empty); - } - else - { - /* FIXME: should we make this configurable? */ - message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty); - } - - gather_and_add_endpoints(this, message); - - break; - } - default: - break; - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case ME_CONNECT: - { - id_payload_t *id_payload; - id_payload = (id_payload_t*)message->get_payload(message, ID_PEER); - if (!id_payload) - { - DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload" - ", aborting"); - break; - } - this->peer_id = id_payload->get_identification(id_payload); - - process_payloads(this, message); - - if (this->callback) - { - DBG1(DBG_IKE, "received ME_CALLBACK for '%Y'", this->peer_id); - break; - } - - if (!this->connect_id.ptr) - { - DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify" - ", aborting"); - this->invalid_syntax = TRUE; - break; - } - - if (!this->connect_key.ptr) - { - DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY " - "notify, aborting"); - this->invalid_syntax = TRUE; - break; - } - - if (!this->remote_endpoints->get_count(this->remote_endpoints)) - { - DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT " - "payloads, aborting"); - this->invalid_syntax = TRUE; - break; - } - - DBG1(DBG_IKE, "received ME_CONNECT"); - break; - } - default: - break; - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case ME_CONNECT: - { - if (this->invalid_syntax) - { - message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty); - break; - } - - if (this->callback) - { - /* we got a callback from the mediation server, initiate the - * queued mediated connecction */ - charon->connect_manager->check_and_initiate( - charon->connect_manager, - this->ike_sa->get_id(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), this->peer_id); - return SUCCESS; - } - - if (this->response) - { - /* FIXME: handle result of set_responder_data - * as initiator, upon receiving a response from another peer, - * update the checklist and start sending checks */ - charon->connect_manager->set_responder_data( - charon->connect_manager, - this->connect_id, this->connect_key, - this->remote_endpoints); - } - else - { - /* FIXME: handle result of set_initiator_data - * as responder, create a checklist with the initiator's data */ - charon->connect_manager->set_initiator_data( - charon->connect_manager, - this->peer_id, this->ike_sa->get_my_id(this->ike_sa), - this->connect_id, this->connect_key, - this->remote_endpoints, FALSE); - if (this->ike_sa->respond(this->ike_sa, this->peer_id, - this->connect_id) != SUCCESS) - { - return FAILED; - } - } - break; - } - default: - break; - } - return SUCCESS; -} - -METHOD(task_t, process_i, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case IKE_SA_INIT: - { - process_payloads(this, message); - if (!this->mediation) - { - DBG1(DBG_IKE, "server did not return a ME_MEDIATION, aborting"); - return FAILED; - } - /* if we are on a mediation connection we switch to port 4500 even - * if no NAT is detected. */ - this->ike_sa->float_ports(this->ike_sa); - return NEED_MORE; - } - case IKE_AUTH: - { - process_payloads(this, message); - /* FIXME: we should update the server reflexive endpoint somehow, - * if mobike notices a change */ - endpoint_notify_t *reflexive; - if (this->remote_endpoints->get_first(this->remote_endpoints, - (void**)&reflexive) == SUCCESS && - reflexive->get_type(reflexive) == SERVER_REFLEXIVE) - { /* FIXME: should we accept this endpoint even if we did not send - * a request? */ - host_t *endpoint = reflexive->get_host(reflexive); - endpoint = endpoint->clone(endpoint); - this->ike_sa->set_server_reflexive_host(this->ike_sa, endpoint); - } - break; - } - case ME_CONNECT: - { - process_payloads(this, message); - - if (this->failed) - { - DBG1(DBG_IKE, "peer '%Y' is not online", this->peer_id); - /* FIXME: notify the mediated connection (job?) */ - } - else - { - if (this->response) - { - /* FIXME: handle result of set_responder_data. */ - /* as responder, we update the checklist and start sending - * checks */ - charon->connect_manager->set_responder_data( - charon->connect_manager, this->connect_id, - this->connect_key, this->local_endpoints); - } - else - { - /* FIXME: handle result of set_initiator_data */ - /* as initiator, we create a checklist and set the - * initiator's data */ - charon->connect_manager->set_initiator_data( - charon->connect_manager, - this->ike_sa->get_my_id(this->ike_sa), - this->peer_id, this->connect_id, this->connect_key, - this->local_endpoints, TRUE); - /* FIXME: also start a timer for the whole transaction - * (maybe within the connect_manager?) */ - } - } - break; - } - default: - break; - } - return SUCCESS; -} - -/** - * For mediation server - */ -METHOD(task_t, build_i_ms, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case ME_CONNECT: - { - id_payload_t *id_payload; - id_payload = id_payload_create_from_identification(ID_PEER, - this->peer_id); - message->add_payload(message, (payload_t*)id_payload); - - if (this->callback) - { - message->add_notify(message, FALSE, ME_CALLBACK, chunk_empty); - } - else - { - if (this->response) - { - message->add_notify(message, FALSE, ME_RESPONSE, - chunk_empty); - } - message->add_notify(message, FALSE, ME_CONNECTID, - this->connect_id); - message->add_notify(message, FALSE, ME_CONNECTKEY, - this->connect_key); - add_endpoints_to_message(message, this->remote_endpoints); - } - break; - } - default: - break; - } - return NEED_MORE; -} - -/** - * For mediation server - */ -METHOD(task_t, process_r_ms, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case IKE_SA_INIT: - { - /* FIXME: we should check for SA* and TS* payloads. if there are - * any, send NO_ADDITIONAL_SAS back and delete this SA */ - process_payloads(this, message); - return this->mediation ? NEED_MORE : SUCCESS; - } - case IKE_AUTH: - { - /* FIXME: we should check whether the current peer_config is - * configured as mediation connection */ - process_payloads(this, message); - break; - } - case CREATE_CHILD_SA: - { - /* FIXME: if this is not to rekey the IKE SA we have to return a - * NO_ADDITIONAL_SAS and then delete the SA */ - break; - } - case ME_CONNECT: - { - id_payload_t *id_payload; - id_payload = (id_payload_t*)message->get_payload(message, ID_PEER); - if (!id_payload) - { - DBG1(DBG_IKE, "received ME_CONNECT without ID_PEER payload" - ", aborting"); - this->invalid_syntax = TRUE; - break; - } - this->peer_id = id_payload->get_identification(id_payload); - - process_payloads(this, message); - - if (!this->connect_id.ptr) - { - DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTID notify" - ", aborting"); - this->invalid_syntax = TRUE; - break; - } - - if (!this->connect_key.ptr) - { - DBG1(DBG_IKE, "received ME_CONNECT without ME_CONNECTKEY notify" - ", aborting"); - this->invalid_syntax = TRUE; - break; - } - - if (!this->remote_endpoints->get_count(this->remote_endpoints)) - { - DBG1(DBG_IKE, "received ME_CONNECT without any ME_ENDPOINT " - "payloads, aborting"); - this->invalid_syntax = TRUE; - break; - } - break; - } - default: - break; - } - return NEED_MORE; -} - -/** - * For mediation server - */ -METHOD(task_t, build_r_ms, status_t, - private_ike_me_t *this, message_t *message) -{ - switch(message->get_exchange_type(message)) - { - case IKE_SA_INIT: - { - message->add_notify(message, FALSE, ME_MEDIATION, chunk_empty); - return NEED_MORE; - } - case IKE_AUTH: - { - endpoint_notify_t *endpoint; - if (this->remote_endpoints->get_first(this->remote_endpoints, - (void**)&endpoint) == SUCCESS && - endpoint->get_type(endpoint) == SERVER_REFLEXIVE) - { - host_t *host = this->ike_sa->get_other_host(this->ike_sa); - DBG2(DBG_IKE, "received request for a server reflexive " - "endpoint sending: %#H", host); - endpoint = endpoint_notify_create_from_host(SERVER_REFLEXIVE, - host, NULL); - message->add_payload(message, (payload_t*)endpoint->build_notify(endpoint)); - endpoint->destroy(endpoint); - } - this->ike_sa->act_as_mediation_server(this->ike_sa); - break; - } - case ME_CONNECT: - { - if (this->invalid_syntax) - { - message->add_notify(message, TRUE, INVALID_SYNTAX, chunk_empty); - break; - } - - ike_sa_id_t *peer_sa; - if (this->callback) - { - peer_sa = charon->mediation_manager->check_and_register( - charon->mediation_manager, this->peer_id, - this->ike_sa->get_other_id(this->ike_sa)); - } - else - { - peer_sa = charon->mediation_manager->check( - charon->mediation_manager, this->peer_id); - } - - if (!peer_sa) - { - /* the peer is not online */ - message->add_notify(message, TRUE, ME_CONNECT_FAILED, - chunk_empty); - break; - } - - job_t *job = (job_t*)mediation_job_create(this->peer_id, - this->ike_sa->get_other_id(this->ike_sa), this->connect_id, - this->connect_key, this->remote_endpoints, this->response); - lib->processor->queue_job(lib->processor, job); - break; - } - default: - break; - } - return SUCCESS; -} - -/** - * For mediation server - */ -METHOD(task_t, process_i_ms, status_t, - private_ike_me_t *this, message_t *message) -{ - /* FIXME: theoretically we should be prepared to receive a ME_CONNECT_FAILED - * here if the responding peer is not able to proceed. in this case we shall - * notify the initiating peer with a ME_CONNECT request containing only a - * ME_CONNECT_FAILED */ - return SUCCESS; -} - -METHOD(ike_me_t, me_connect, void, - private_ike_me_t *this, identification_t *peer_id) -{ - this->peer_id = peer_id->clone(peer_id); -} - -METHOD(ike_me_t, me_respond, void, - private_ike_me_t *this, identification_t *peer_id, chunk_t connect_id) -{ - this->peer_id = peer_id->clone(peer_id); - this->connect_id = chunk_clone(connect_id); - this->response = TRUE; -} - -METHOD(ike_me_t, me_callback, void, - private_ike_me_t *this, identification_t *peer_id) -{ - this->peer_id = peer_id->clone(peer_id); - this->callback = TRUE; -} - -METHOD(ike_me_t, relay, void, - private_ike_me_t *this, identification_t *requester, chunk_t connect_id, - chunk_t connect_key, linked_list_t *endpoints, bool response) -{ - this->peer_id = requester->clone(requester); - this->connect_id = chunk_clone(connect_id); - this->connect_key = chunk_clone(connect_key); - - this->remote_endpoints->destroy_offset(this->remote_endpoints, - offsetof(endpoint_notify_t, destroy)); - this->remote_endpoints = endpoints->clone_offset(endpoints, - offsetof(endpoint_notify_t, clone)); - - this->response = response; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_me_t *this) -{ - return IKE_ME; -} - -METHOD(task_t, migrate, void, - private_ike_me_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; -} - -METHOD(task_t, destroy, void, - private_ike_me_t *this) -{ - DESTROY_IF(this->peer_id); - - chunk_free(&this->connect_id); - chunk_free(&this->connect_key); - - this->local_endpoints->destroy_offset(this->local_endpoints, - offsetof(endpoint_notify_t, destroy)); - this->remote_endpoints->destroy_offset(this->remote_endpoints, - offsetof(endpoint_notify_t, destroy)); - - DESTROY_IF(this->mediated_cfg); - free(this); -} - -/* - * Described in header. - */ -ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_me_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .connect = _me_connect, - .respond = _me_respond, - .callback = _me_callback, - .relay = _relay, - }, - .ike_sa = ike_sa, - .initiator = initiator, - .local_endpoints = linked_list_create(), - .remote_endpoints = linked_list_create(), - ); - - if (ike_sa->has_condition(ike_sa, COND_ORIGINAL_INITIATOR)) - { - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - } - else - { - /* mediation server */ - if (initiator) - { - this->public.task.build = _build_i_ms; - this->public.task.process = _process_i_ms; - } - else - { - this->public.task.build = _build_r_ms; - this->public.task.process = _process_r_ms; - } - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_me.h b/src/libcharon/sa/tasks/ike_me.h deleted file mode 100644 index 31285a426..000000000 --- a/src/libcharon/sa/tasks/ike_me.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2007 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_me ike_me - * @{ @ingroup tasks - */ - -#ifndef IKE_ME_H_ -#define IKE_ME_H_ - -typedef struct ike_me_t ike_me_t; - -#include -#include -#include - -/** - * Task of type IKE_ME, detects and handles IKE-ME extensions. - * - * This tasks handles the ME_MEDIATION Notify exchange to setup a mediation - * connection, allows to initiate mediated connections using ME_CONNECT - * exchanges and to request reflexive addresses from the mediation server using - * ME_ENDPOINT notifies. - * - * @note This task has to be activated before the IKE_AUTH task, because that - * task generates the IKE_SA_INIT message so that no more payloads can be added - * to it afterwards. - */ -struct ike_me_t { - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Initiates a connection with another peer (i.e. sends a ME_CONNECT - * to the mediation server) - * - * @param peer_id ID of the other peer (gets cloned) - */ - void (*connect)(ike_me_t *this, identification_t *peer_id); - - /** - * Responds to a ME_CONNECT from another peer (i.e. sends a ME_CONNECT - * to the mediation server) - * - * Data gets cloned. - * - * @param peer_id ID of the other peer - * @param connect_id the connect ID as provided by the initiator - */ - void (*respond)(ike_me_t *this, identification_t *peer_id, - chunk_t connect_id); - - /** - * Sends a ME_CALLBACK to a peer that previously requested some other peer. - * - * @param peer_id ID of the other peer (gets cloned) - */ - void (*callback)(ike_me_t *this, identification_t *peer_id); - - /** - * Relays data to another peer (i.e. sends a ME_CONNECT to the peer) - * - * Data gets cloned. - * - * @param requester ID of the requesting peer - * @param connect_id content of the ME_CONNECTID notify - * @param connect_key content of the ME_CONNECTKEY notify - * @param endpoints endpoints - * @param response TRUE if this is a response - */ - void (*relay)(ike_me_t *this, identification_t *requester, - chunk_t connect_id, chunk_t connect_key, - linked_list_t *endpoints, bool response); -}; - -/** - * Create a new ike_me task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is initiated by us - * @return ike_me task to be handled by the task_manager - */ -ike_me_t *ike_me_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_ME_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_mobike.c b/src/libcharon/sa/tasks/ike_mobike.c deleted file mode 100644 index fb1100028..000000000 --- a/src/libcharon/sa/tasks/ike_mobike.c +++ /dev/null @@ -1,649 +0,0 @@ -/* - * Copyright (C) 2010-2012 Tobias Brunner - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_mobike.h" - -#include - -#include -#include -#include -#include - -#define COOKIE2_SIZE 16 -#define MAX_ADDITIONAL_ADDRS 8 - -typedef struct private_ike_mobike_t private_ike_mobike_t; - -/** - * Private members of a ike_mobike_t task. - */ -struct private_ike_mobike_t { - - /** - * Public methods and task_t interface. - */ - ike_mobike_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * cookie2 value to verify new addresses - */ - chunk_t cookie2; - - /** - * NAT discovery reusing the IKE_NATD task - */ - ike_natd_t *natd; - - /** - * use task to update addresses - */ - bool update; - - /** - * do routability check - */ - bool check; - - /** - * include address list update - */ - bool address; - - /** - * additional addresses got updated - */ - bool addresses_updated; -}; - -/** - * read notifys from message and evaluate them - */ -static void process_payloads(private_ike_mobike_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - bool first = TRUE; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - int family = AF_INET; - notify_payload_t *notify; - chunk_t data; - host_t *host; - - if (payload->get_type(payload) != NOTIFY) - { - continue; - } - notify = (notify_payload_t*)payload; - switch (notify->get_notify_type(notify)) - { - case MOBIKE_SUPPORTED: - { - peer_cfg_t *peer_cfg; - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (!this->initiator && - peer_cfg && !peer_cfg->use_mobike(peer_cfg)) - { - DBG1(DBG_IKE, "peer supports MOBIKE, but disabled in config"); - } - else - { - DBG1(DBG_IKE, "peer supports MOBIKE"); - this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE); - } - break; - } - case COOKIE2: - { - chunk_free(&this->cookie2); - this->cookie2 = chunk_clone(notify->get_notification_data(notify)); - break; - } - case ADDITIONAL_IP6_ADDRESS: - { - family = AF_INET6; - /* fall through */ - } - case ADDITIONAL_IP4_ADDRESS: - { - if (first) - { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */ - this->ike_sa->clear_peer_addresses(this->ike_sa); - first = FALSE; - /* add the peer's current address to the list */ - host = message->get_source(message); - this->ike_sa->add_peer_address(this->ike_sa, - host->clone(host)); - } - data = notify->get_notification_data(notify); - host = host_create_from_chunk(family, data, 0); - DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host); - this->ike_sa->add_peer_address(this->ike_sa, host); - this->addresses_updated = TRUE; - break; - } - case UPDATE_SA_ADDRESSES: - { - this->update = TRUE; - break; - } - case NO_ADDITIONAL_ADDRESSES: - { - this->ike_sa->clear_peer_addresses(this->ike_sa); - /* add the peer's current address to the list */ - host = message->get_source(message); - this->ike_sa->add_peer_address(this->ike_sa, host->clone(host)); - this->addresses_updated = TRUE; - break; - } - case NAT_DETECTION_SOURCE_IP: - case NAT_DETECTION_DESTINATION_IP: - { - /* NAT check in this MOBIKE exchange, create subtask for it */ - if (this->natd == NULL) - { - this->natd = ike_natd_create(this->ike_sa, this->initiator); - } - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * Add ADDITIONAL_*_ADDRESS notifys depending on our address list - */ -static void build_address_list(private_ike_mobike_t *this, message_t *message) -{ - enumerator_t *enumerator; - host_t *host, *me; - notify_type_t type; - int added = 0; - - me = this->ike_sa->get_my_host(this->ike_sa); - enumerator = hydra->kernel_interface->create_address_enumerator( - hydra->kernel_interface, FALSE, FALSE); - while (enumerator->enumerate(enumerator, (void**)&host)) - { - if (me->ip_equals(me, host)) - { /* "ADDITIONAL" means do not include IKE_SAs host */ - continue; - } - switch (host->get_family(host)) - { - case AF_INET: - type = ADDITIONAL_IP4_ADDRESS; - break; - case AF_INET6: - type = ADDITIONAL_IP6_ADDRESS; - break; - default: - continue; - } - message->add_notify(message, FALSE, type, host->get_address(host)); - if (++added >= MAX_ADDITIONAL_ADDRS) - { /* limit number of notifys, some implementations do not like too - * many of them (f.e. strongSwan ;-) */ - break; - } - } - if (!added) - { - message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty); - } - enumerator->destroy(enumerator); -} - -/** - * build a cookie and add it to the message - */ -static void build_cookie(private_ike_mobike_t *this, message_t *message) -{ - rng_t *rng; - - chunk_free(&this->cookie2); - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (rng) - { - rng->allocate_bytes(rng, COOKIE2_SIZE, &this->cookie2); - rng->destroy(rng); - message->add_notify(message, FALSE, COOKIE2, this->cookie2); - } -} - -/** - * update addresses of associated CHILD_SAs - */ -static void update_children(private_ike_mobike_t *this) -{ - enumerator_t *enumerator; - child_sa_t *child_sa; - - enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - if (child_sa->update(child_sa, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_virtual_ip(this->ike_sa, TRUE), - this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED) - { - this->ike_sa->rekey_child_sa(this->ike_sa, - child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); - } - } - enumerator->destroy(enumerator); -} - -/** - * Apply the port of the old host, if its ip equals the new, use port otherwise. - */ -static void apply_port(host_t *host, host_t *old, u_int16_t port) -{ - if (host->ip_equals(host, old)) - { - port = old->get_port(old); - } - else if (port == IKEV2_UDP_PORT) - { - port = IKEV2_NATT_PORT; - } - host->set_port(host, port); -} - -METHOD(ike_mobike_t, transmit, void, - private_ike_mobike_t *this, packet_t *packet) -{ - host_t *me, *other, *me_old, *other_old; - enumerator_t *enumerator; - ike_cfg_t *ike_cfg; - packet_t *copy; - - if (!this->check) - { - return; - } - - me_old = this->ike_sa->get_my_host(this->ike_sa); - other_old = this->ike_sa->get_other_host(this->ike_sa); - ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - - enumerator = this->ike_sa->create_peer_address_enumerator(this->ike_sa); - while (enumerator->enumerate(enumerator, (void**)&other)) - { - me = hydra->kernel_interface->get_source_addr( - hydra->kernel_interface, other, NULL); - if (me) - { - if (me->get_family(me) != other->get_family(other)) - { - me->destroy(me); - continue; - } - /* reuse port for an active address, 4500 otherwise */ - apply_port(me, me_old, ike_cfg->get_my_port(ike_cfg)); - other = other->clone(other); - apply_port(other, other_old, ike_cfg->get_other_port(ike_cfg)); - DBG1(DBG_IKE, "checking path %#H - %#H", me, other); - copy = packet->clone(packet); - copy->set_source(copy, me); - copy->set_destination(copy, other); - charon->sender->send(charon->sender, copy); - } - } - enumerator->destroy(enumerator); -} - -METHOD(task_t, build_i, status_t, - private_ike_mobike_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) - { /* only in first IKE_AUTH */ - message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); - build_address_list(this, message); - } - else if (message->get_exchange_type(message) == INFORMATIONAL) - { - host_t *old, *new; - - /* we check if the existing address is still valid */ - old = message->get_source(message); - new = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, - message->get_destination(message), old); - if (new) - { - if (!new->ip_equals(new, old)) - { - new->set_port(new, old->get_port(old)); - message->set_source(message, new); - } - else - { - new->destroy(new); - } - } - if (this->update) - { - message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, - chunk_empty); - build_cookie(this, message); - update_children(this); - } - if (this->address && !this->check) - { - build_address_list(this, message); - } - if (this->natd) - { - this->natd->task.build(&this->natd->task, message); - } - } - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_mobike_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) - { /* only first IKE_AUTH */ - process_payloads(this, message); - } - else if (message->get_exchange_type(message) == INFORMATIONAL) - { - process_payloads(this, message); - if (this->update) - { - host_t *me, *other; - - me = message->get_destination(message); - other = message->get_source(message); - this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); - this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); - } - - if (this->natd) - { - this->natd->task.process(&this->natd->task, message); - } - if (this->addresses_updated && this->ike_sa->has_condition(this->ike_sa, - COND_ORIGINAL_INITIATOR)) - { - host_t *other = message->get_source(message); - host_t *other_old = this->ike_sa->get_other_host(this->ike_sa); - if (!other->equals(other, other_old)) - { - DBG1(DBG_IKE, "remote address changed from %H to %H", other_old, - other); - this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); - this->update = TRUE; - } - } - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_mobike_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { - if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) - { - message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); - build_address_list(this, message); - } - return SUCCESS; - } - else if (message->get_exchange_type(message) == INFORMATIONAL) - { - if (this->natd) - { - this->natd->task.build(&this->natd->task, message); - } - if (this->cookie2.ptr) - { - message->add_notify(message, FALSE, COOKIE2, this->cookie2); - chunk_free(&this->cookie2); - } - if (this->update) - { - update_children(this); - } - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_mobike_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_AUTH && - this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { - process_payloads(this, message); - return SUCCESS; - } - else if (message->get_exchange_type(message) == INFORMATIONAL) - { - u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1; - this->ike_sa->set_pending_updates(this->ike_sa, updates); - if (updates > 0) - { - /* newer update queued, ignore this one */ - return SUCCESS; - } - if (this->cookie2.ptr) - { /* check cookie if we included one */ - chunk_t cookie2; - - cookie2 = this->cookie2; - this->cookie2 = chunk_empty; - process_payloads(this, message); - if (!chunk_equals(cookie2, this->cookie2)) - { - chunk_free(&cookie2); - DBG1(DBG_IKE, "COOKIE2 mismatch, closing IKE_SA"); - return FAILED; - } - chunk_free(&cookie2); - } - else - { - process_payloads(this, message); - } - if (this->natd) - { - this->natd->task.process(&this->natd->task, message); - if (this->natd->has_mapping_changed(this->natd)) - { - /* force an update if mappings have changed */ - this->update = this->check = TRUE; - DBG1(DBG_IKE, "detected changes in NAT mappings, " - "initiating MOBIKE update"); - } - } - if (this->update) - { - /* update again, as NAT state may have changed */ - update_children(this); - } - if (this->check) - { - host_t *me_new, *me_old, *other_new, *other_old; - - me_new = message->get_destination(message); - other_new = message->get_source(message); - me_old = this->ike_sa->get_my_host(this->ike_sa); - other_old = this->ike_sa->get_other_host(this->ike_sa); - - if (!me_new->equals(me_new, me_old)) - { - this->update = TRUE; - this->ike_sa->set_my_host(this->ike_sa, me_new->clone(me_new)); - } - if (!other_new->equals(other_new, other_old)) - { - this->update = TRUE; - this->ike_sa->set_other_host(this->ike_sa, other_new->clone(other_new)); - } - if (this->update) - { - /* use the same task to ... */ - if (!this->ike_sa->has_condition(this->ike_sa, - COND_ORIGINAL_INITIATOR)) - { /*... send an updated list of addresses as responder */ - update_children(this); - this->update = FALSE; - } - else - { /* ... send the update as original initiator */ - if (this->natd) - { - this->natd->task.destroy(&this->natd->task); - } - this->natd = ike_natd_create(this->ike_sa, this->initiator); - } - this->check = FALSE; - this->ike_sa->set_pending_updates(this->ike_sa, 1); - return NEED_MORE; - } - } - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(ike_mobike_t, addresses, void, - private_ike_mobike_t *this) -{ - this->address = TRUE; - this->ike_sa->set_pending_updates(this->ike_sa, - this->ike_sa->get_pending_updates(this->ike_sa) + 1); -} - -METHOD(ike_mobike_t, roam, void, - private_ike_mobike_t *this, bool address) -{ - this->check = TRUE; - this->address = address; - this->ike_sa->set_pending_updates(this->ike_sa, - this->ike_sa->get_pending_updates(this->ike_sa) + 1); -} - -METHOD(ike_mobike_t, dpd, void, - private_ike_mobike_t *this) -{ - if (!this->natd) - { - this->natd = ike_natd_create(this->ike_sa, this->initiator); - } - this->ike_sa->set_pending_updates(this->ike_sa, - this->ike_sa->get_pending_updates(this->ike_sa) + 1); -} - -METHOD(ike_mobike_t, is_probing, bool, - private_ike_mobike_t *this) -{ - return this->check; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_mobike_t *this) -{ - return IKE_MOBIKE; -} - -METHOD(task_t, migrate, void, - private_ike_mobike_t *this, ike_sa_t *ike_sa) -{ - chunk_free(&this->cookie2); - this->ike_sa = ike_sa; - if (this->natd) - { - this->natd->task.migrate(&this->natd->task, ike_sa); - } -} - -METHOD(task_t, destroy, void, - private_ike_mobike_t *this) -{ - chunk_free(&this->cookie2); - if (this->natd) - { - this->natd->task.destroy(&this->natd->task); - } - free(this); -} - -/* - * Described in header. - */ -ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_mobike_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .addresses = _addresses, - .roam = _roam, - .dpd = _dpd, - .transmit = _transmit, - .is_probing = _is_probing, - }, - .ike_sa = ike_sa, - .initiator = initiator, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_mobike.h b/src/libcharon/sa/tasks/ike_mobike.h deleted file mode 100644 index 16611939e..000000000 --- a/src/libcharon/sa/tasks/ike_mobike.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_mobike ike_mobike - * @{ @ingroup tasks - */ - -#ifndef IKE_MOBIKE_H_ -#define IKE_MOBIKE_H_ - -typedef struct ike_mobike_t ike_mobike_t; - -#include -#include -#include -#include - -/** - * Task of type ike_mobike, detects and handles MOBIKE extension. - * - * The MOBIKE extension is defined in RFC4555. It allows to update IKE - * and IPsec tunnel addresses. - * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE - * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional - * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update - * endpoints. - */ -struct ike_mobike_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Use the task to update the list of additional addresses. - */ - void (*addresses)(ike_mobike_t *this); - - /** - * Use the task to roam to other addresses. - * - * @param address TRUE to include address list update - */ - void (*roam)(ike_mobike_t *this, bool address); - - /** - * Use the task for a DPD check which detects changes in NAT mappings. - */ - void (*dpd)(ike_mobike_t *this); - - /** - * Transmision hook, called by task manager. - * - * The task manager calls this hook whenever it transmits a packet. It - * allows the mobike task to send the packet on multiple paths to do path - * probing. - * - * @param packet the packet to transmit - */ - void (*transmit)(ike_mobike_t *this, packet_t *packet); - - /** - * Check if this task is probing for routability. - * - * @return TRUE if task is probing - */ - bool (*is_probing)(ike_mobike_t *this); -}; - -/** - * Create a new ike_mobike task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if taks is initiated by us - * @return ike_mobike task to handle by the task_manager - */ -ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_MOBIKE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/tasks/ike_natd.c deleted file mode 100644 index f06a518fa..000000000 --- a/src/libcharon/sa/tasks/ike_natd.c +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2006-2007 Martin Willi - * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_natd.h" - -#include - -#include -#include -#include -#include -#include - - -typedef struct private_ike_natd_t private_ike_natd_t; - -/** - * Private members of a ike_natd_t task. - */ -struct private_ike_natd_t { - - /** - * Public methods and task_t interface. - */ - ike_natd_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * Hasher used to build NAT detection hashes - */ - hasher_t *hasher; - - /** - * Did we process any NAT detection notifys for a source address? - */ - bool src_seen; - - /** - * Did we process any NAT detection notifys for a destination address? - */ - bool dst_seen; - - /** - * Have we found a matching source address NAT hash? - */ - bool src_matched; - - /** - * Have we found a matching destination address NAT hash? - */ - bool dst_matched; - - /** - * whether NAT mappings for our NATed address has changed - */ - bool mapping_changed; -}; - - -/** - * Build NAT detection hash for a host - */ -static chunk_t generate_natd_hash(private_ike_natd_t *this, - ike_sa_id_t *ike_sa_id, host_t *host) -{ - chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk; - chunk_t natd_hash; - u_int64_t spi_i, spi_r; - u_int16_t port; - - /* prepare all required chunks */ - spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); - spi_r = ike_sa_id->get_responder_spi(ike_sa_id); - spi_i_chunk.ptr = (void*)&spi_i; - spi_i_chunk.len = sizeof(spi_i); - spi_r_chunk.ptr = (void*)&spi_r; - spi_r_chunk.len = sizeof(spi_r); - port = htons(host->get_port(host)); - port_chunk.ptr = (void*)&port; - port_chunk.len = sizeof(port); - addr_chunk = host->get_address(host); - - /* natd_hash = SHA1( spi_i | spi_r | address | port ) */ - natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk); - this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash); - DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk); - DBG3(DBG_IKE, "natd_hash %B", &natd_hash); - - chunk_free(&natd_chunk); - return natd_hash; -} - -/** - * build a faked NATD payload to enforce UDP encap - */ -static chunk_t generate_natd_hash_faked(private_ike_natd_t *this) -{ - rng_t *rng; - chunk_t chunk; - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_IKE, "unable to get random bytes for NATD fake"); - return chunk_empty; - } - rng->allocate_bytes(rng, HASH_SIZE_SHA1, &chunk); - rng->destroy(rng); - return chunk; -} - -/** - * Build a NAT detection notify payload. - */ -static notify_payload_t *build_natd_payload(private_ike_natd_t *this, - notify_type_t type, host_t *host) -{ - chunk_t hash; - notify_payload_t *notify; - ike_sa_id_t *ike_sa_id; - ike_cfg_t *config; - - ike_sa_id = this->ike_sa->get_id(this->ike_sa); - config = this->ike_sa->get_ike_cfg(this->ike_sa); - if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP) - { - hash = generate_natd_hash_faked(this); - } - else - { - hash = generate_natd_hash(this, ike_sa_id, host); - } - notify = notify_payload_create(); - notify->set_notify_type(notify, type); - notify->set_notification_data(notify, hash); - chunk_free(&hash); - - return notify; -} - -/** - * read notifys from message and evaluate them - */ -static void process_payloads(private_ike_natd_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - notify_payload_t *notify; - chunk_t hash, src_hash, dst_hash; - ike_sa_id_t *ike_sa_id; - host_t *me, *other; - ike_cfg_t *config; - - /* Precompute NAT-D hashes for incoming NAT notify comparison */ - ike_sa_id = message->get_ike_sa_id(message); - me = message->get_destination(message); - other = message->get_source(message); - dst_hash = generate_natd_hash(this, ike_sa_id, me); - src_hash = generate_natd_hash(this, ike_sa_id, other); - - DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); - DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) != NOTIFY) - { - continue; - } - notify = (notify_payload_t*)payload; - switch (notify->get_notify_type(notify)) - { - case NAT_DETECTION_DESTINATION_IP: - { - this->dst_seen = TRUE; - hash = notify->get_notification_data(notify); - if (!this->dst_matched) - { - DBG3(DBG_IKE, "received dst_hash %B", &hash); - if (chunk_equals(hash, dst_hash)) - { - this->dst_matched = TRUE; - } - } - /* RFC4555 says we should also compare against IKE_SA_INIT - * NATD payloads, but this does not work: We are running - * there at port 500, but use 4500 afterwards... */ - if (message->get_exchange_type(message) == INFORMATIONAL && - this->initiator && !this->dst_matched) - { - this->mapping_changed = this->ike_sa->has_mapping_changed( - this->ike_sa, hash); - } - break; - } - case NAT_DETECTION_SOURCE_IP: - { - this->src_seen = TRUE; - if (!this->src_matched) - { - hash = notify->get_notification_data(notify); - DBG3(DBG_IKE, "received src_hash %B", &hash); - if (chunk_equals(hash, src_hash)) - { - this->src_matched = TRUE; - } - } - break; - } - default: - break; - } - } - enumerator->destroy(enumerator); - - chunk_free(&src_hash); - chunk_free(&dst_hash); - - if (this->src_seen && this->dst_seen) - { - this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); - - this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, - !this->dst_matched); - this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, - !this->src_matched); - config = this->ike_sa->get_ike_cfg(this->ike_sa); - if (this->dst_matched && this->src_matched && - config->force_encap(config)) - { - this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE); - } - } -} - -METHOD(task_t, process_i, status_t, - private_ike_natd_t *this, message_t *message) -{ - process_payloads(this, message); - - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY) || - /* if peer supports NAT-T, we switch to port 4500 even - * if no NAT is detected. can't be done later (when we would know - * whether the peer supports MOBIKE) because there would be no - * exchange to actually do the switch (other than a forced DPD). */ - (peer_cfg->use_mobike(peer_cfg) && - this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))) - { - this->ike_sa->float_ports(this->ike_sa); - } - } - - return SUCCESS; -} - -METHOD(task_t, build_i, status_t, - private_ike_natd_t *this, message_t *message) -{ - notify_payload_t *notify; - enumerator_t *enumerator; - ike_cfg_t *ike_cfg; - host_t *host; - - if (this->hasher == NULL) - { - DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); - return NEED_MORE; - } - - ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - - /* destination is always set */ - host = message->get_destination(message); - notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host); - message->add_payload(message, (payload_t*)notify); - - /* source may be any, we have 3 possibilities to get our source address: - * 1. It is defined in the config => use the one of the IKE_SA - * 2. We do a routing lookup in the kernel interface - * 3. Include all possbile addresses - */ - host = message->get_source(message); - if (!host->is_anyaddr(host)) - { /* 1. */ - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - message->add_payload(message, (payload_t*)notify); - } - else - { - host = hydra->kernel_interface->get_source_addr(hydra->kernel_interface, - this->ike_sa->get_other_host(this->ike_sa), NULL); - if (host) - { /* 2. */ - host->set_port(host, ike_cfg->get_my_port(ike_cfg)); - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - message->add_payload(message, (payload_t*)notify); - host->destroy(host); - } - else - { /* 3. */ - enumerator = hydra->kernel_interface->create_address_enumerator( - hydra->kernel_interface, FALSE, FALSE); - while (enumerator->enumerate(enumerator, (void**)&host)) - { - /* apply port 500 to host, but work on a copy */ - host = host->clone(host); - host->set_port(host, ike_cfg->get_my_port(ike_cfg)); - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host); - host->destroy(host); - message->add_payload(message, (payload_t*)notify); - } - enumerator->destroy(enumerator); - } - } - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_natd_t *this, message_t *message) -{ - notify_payload_t *notify; - host_t *me, *other; - - /* only add notifies on successful responses. */ - if (message->get_exchange_type(message) == IKE_SA_INIT && - message->get_payload(message, SECURITY_ASSOCIATION) == NULL) - { - return SUCCESS; - } - - if (this->src_seen && this->dst_seen) - { - if (this->hasher == NULL) - { - DBG1(DBG_IKE, "unable to build NATD payloads, SHA1 not supported"); - return SUCCESS; - } - - /* initiator seems to support NAT detection, add response */ - me = message->get_source(message); - notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me); - message->add_payload(message, (payload_t*)notify); - - other = message->get_destination(message); - notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other); - message->add_payload(message, (payload_t*)notify); - } - return SUCCESS; -} - -METHOD(task_t, process_r, status_t, - private_ike_natd_t *this, message_t *message) -{ - process_payloads(this, message); - - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_natd_t *this) -{ - return IKE_NATD; -} - -METHOD(task_t, migrate, void, - private_ike_natd_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; - this->src_seen = FALSE; - this->dst_seen = FALSE; - this->src_matched = FALSE; - this->dst_matched = FALSE; - this->mapping_changed = FALSE; -} - -METHOD(task_t, destroy, void, - private_ike_natd_t *this) -{ - DESTROY_IF(this->hasher); - free(this); -} - -METHOD(ike_natd_t, has_mapping_changed, bool, - private_ike_natd_t *this) -{ - return this->mapping_changed; -} - -/* - * Described in header. - */ -ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_natd_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - }, - .has_mapping_changed = _has_mapping_changed, - }, - .ike_sa = ike_sa, - .initiator = initiator, - .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_natd.h b/src/libcharon/sa/tasks/ike_natd.h deleted file mode 100644 index 68114af42..000000000 --- a/src/libcharon/sa/tasks/ike_natd.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_natd ike_natd - * @{ @ingroup tasks - */ - -#ifndef IKE_NATD_H_ -#define IKE_NATD_H_ - -typedef struct ike_natd_t ike_natd_t; - -#include -#include -#include - -/** - * Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange. - */ -struct ike_natd_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Check if the NAT mapping has changed for our address. - * - * MOBIKE uses NAT payloads in DPD to detect changes in the NAT mappings. - * - * @return TRUE if mappings have changed - */ - bool (*has_mapping_changed)(ike_natd_t *this); -}; - -/** - * Create a new ike_natd task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is the original initiator - * @return ike_natd task to handle by the task_manager - */ -ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_NATD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_reauth.c b/src/libcharon/sa/tasks/ike_reauth.c deleted file mode 100644 index 48002d81c..000000000 --- a/src/libcharon/sa/tasks/ike_reauth.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2006-2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_reauth.h" - -#include -#include - - -typedef struct private_ike_reauth_t private_ike_reauth_t; - -/** - * Private members of a ike_reauth_t task. - */ -struct private_ike_reauth_t { - - /** - * Public methods and task_t interface. - */ - ike_reauth_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * reused ike_delete task - */ - ike_delete_t *ike_delete; -}; - -METHOD(task_t, build_i, status_t, - private_ike_reauth_t *this, message_t *message) -{ - return this->ike_delete->task.build(&this->ike_delete->task, message); -} - -METHOD(task_t, process_i, status_t, - private_ike_reauth_t *this, message_t *message) -{ - /* process delete response first */ - this->ike_delete->task.process(&this->ike_delete->task, message); - - /* reestablish the IKE_SA with all children */ - if (this->ike_sa->reestablish(this->ike_sa) != SUCCESS) - { - DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); - return FAILED; - } - - /* we always destroy the obsolete IKE_SA */ - return DESTROY_ME; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_reauth_t *this) -{ - return IKE_REAUTH; -} - -METHOD(task_t, migrate, void, - private_ike_reauth_t *this, ike_sa_t *ike_sa) -{ - this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa); - this->ike_sa = ike_sa; -} - -METHOD(task_t, destroy, void, - private_ike_reauth_t *this) -{ - this->ike_delete->task.destroy(&this->ike_delete->task); - free(this); -} - -/* - * Described in header. - */ -ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) -{ - private_ike_reauth_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .build = _build_i, - .process = _process_i, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .ike_delete = ike_delete_create(ike_sa, TRUE), - ); - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_reauth.h b/src/libcharon/sa/tasks/ike_reauth.h deleted file mode 100644 index 5e97b719c..000000000 --- a/src/libcharon/sa/tasks/ike_reauth.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_reauth ike_reauth - * @{ @ingroup tasks - */ - -#ifndef IKE_REAUTH_H_ -#define IKE_REAUTH_H_ - -typedef struct ike_reauth_t ike_reauth_t; - -#include -#include -#include - -/** - * Task of type ike_reauth, reestablishes an IKE_SA. - */ -struct ike_reauth_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new ike_reauth task. - * - * This task is initiator only. - * - * @param ike_sa IKE_SA this task works for - * @return ike_reauth task to handle by the task_manager - */ -ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa); - -#endif /** IKE_REAUTH_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c deleted file mode 100644 index 826d6e192..000000000 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_rekey.h" - -#include -#include -#include -#include -#include -#include - - -typedef struct private_ike_rekey_t private_ike_rekey_t; - -/** - * Private members of a ike_rekey_t task. - */ -struct private_ike_rekey_t { - - /** - * Public methods and task_t interface. - */ - ike_rekey_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * New IKE_SA which replaces the current one - */ - ike_sa_t *new_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * the IKE_INIT task which is reused to simplify rekeying - */ - ike_init_t *ike_init; - - /** - * IKE_DELETE task to delete the old IKE_SA after rekeying was successful - */ - ike_delete_t *ike_delete; - - /** - * colliding task detected by the task manager - */ - task_t *collision; -}; - -/** - * Establish the new replacement IKE_SA - */ -static void establish_new(private_ike_rekey_t *this) -{ - if (this->new_sa) - { - this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] rekeyed between %H[%Y]...%H[%Y]", - this->new_sa->get_name(this->new_sa), - this->new_sa->get_unique_id(this->new_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - this->new_sa->inherit(this->new_sa, this->ike_sa); - charon->bus->ike_rekey(charon->bus, this->ike_sa, this->new_sa); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa); - this->new_sa = NULL; - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - } -} - -METHOD(task_t, process_r_delete, status_t, - private_ike_rekey_t *this, message_t *message) -{ - establish_new(this); - return this->ike_delete->task.process(&this->ike_delete->task, message); -} - -METHOD(task_t, build_r_delete, status_t, - private_ike_rekey_t *this, message_t *message) -{ - return this->ike_delete->task.build(&this->ike_delete->task, message); -} - -METHOD(task_t, build_i_delete, status_t, - private_ike_rekey_t *this, message_t *message) -{ - /* update exchange type to INFORMATIONAL for the delete */ - message->set_exchange_type(message, INFORMATIONAL); - - return this->ike_delete->task.build(&this->ike_delete->task, message); -} - -METHOD(task_t, process_i_delete, status_t, - private_ike_rekey_t *this, message_t *message) -{ - return this->ike_delete->task.process(&this->ike_delete->task, message); -} - -METHOD(task_t, build_i, status_t, - private_ike_rekey_t *this, message_t *message) -{ - peer_cfg_t *peer_cfg; - host_t *other_host; - - /* create new SA only on first try */ - if (this->new_sa == NULL) - { - this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - TRUE); - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - other_host = this->ike_sa->get_other_host(this->ike_sa); - this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); - this->new_sa->set_other_host(this->new_sa, other_host->clone(other_host)); - this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); - this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); - } - this->ike_init->task.build(&this->ike_init->task, message); - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_ike_rekey_t *this, message_t *message) -{ - enumerator_t *enumerator; - peer_cfg_t *peer_cfg; - child_sa_t *child_sa; - - if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING) - { - DBG1(DBG_IKE, "peer initiated rekeying, but we are deleting"); - return NEED_MORE; - } - - enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); - while (enumerator->enumerate(enumerator, (void**)&child_sa)) - { - switch (child_sa->get_state(child_sa)) - { - case CHILD_CREATED: - case CHILD_REKEYING: - case CHILD_DELETING: - /* we do not allow rekeying while we have children in-progress */ - DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open"); - enumerator->destroy(enumerator); - return NEED_MORE; - default: - break; - } - } - enumerator->destroy(enumerator); - - this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - FALSE); - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); - this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa); - this->ike_init->task.process(&this->ike_init->task, message); - - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_ike_rekey_t *this, message_t *message) -{ - if (this->new_sa == NULL) - { - /* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */ - message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); - return SUCCESS; - } - - if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED) - { - return SUCCESS; - } - - this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); - - /* rekeying successful, delete the IKE_SA using a subtask */ - this->ike_delete = ike_delete_create(this->ike_sa, FALSE); - this->public.task.build = _build_r_delete; - this->public.task.process = _process_r_delete; - - return NEED_MORE; -} - -METHOD(task_t, process_i, status_t, - private_ike_rekey_t *this, message_t *message) -{ - if (message->get_notify(message, NO_ADDITIONAL_SAS)) - { - DBG1(DBG_IKE, "peer seems to not support IKE rekeying, " - "starting reauthentication"); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - lib->processor->queue_job(lib->processor, - (job_t*)rekey_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), TRUE)); - return SUCCESS; - } - - switch (this->ike_init->task.process(&this->ike_init->task, message)) - { - case FAILED: - /* rekeying failed, fallback to old SA */ - if (!(this->collision && ( - this->collision->get_type(this->collision) == IKE_DELETE || - this->collision->get_type(this->collision) == IKE_REAUTH))) - { - job_t *job; - u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); - job = (job_t*)rekey_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), FALSE); - DBG1(DBG_IKE, "IKE_SA rekeying failed, " - "trying again in %d seconds", retry); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - lib->scheduler->schedule_job(lib->scheduler, job, retry); - } - return SUCCESS; - case NEED_MORE: - /* bad dh group, try again */ - this->ike_init->task.migrate(&this->ike_init->task, this->new_sa); - return NEED_MORE; - default: - break; - } - - /* check for collisions */ - if (this->collision && - this->collision->get_type(this->collision) == IKE_REKEY) - { - private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision; - - /* ike_init can be NULL, if child_sa is half-open */ - if (other->ike_init) - { - host_t *host; - chunk_t this_nonce, other_nonce; - - this_nonce = this->ike_init->get_lower_nonce(this->ike_init); - other_nonce = other->ike_init->get_lower_nonce(other->ike_init); - - /* if we have the lower nonce, delete rekeyed SA. If not, delete - * the redundant. */ - if (memcmp(this_nonce.ptr, other_nonce.ptr, - min(this_nonce.len, other_nonce.len)) > 0) - { - /* peer should delete this SA. Add a timeout just in case. */ - job_t *job = (job_t*)delete_ike_sa_job_create( - other->new_sa->get_id(other->new_sa), TRUE); - lib->scheduler->schedule_job(lib->scheduler, job, 10); - DBG1(DBG_IKE, "IKE_SA rekey collision won, waiting for delete"); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); - other->new_sa = NULL; - } - else - { - DBG1(DBG_IKE, "IKE_SA rekey collision lost, " - "deleting redundant IKE_SA"); - /* apply host for a proper delete */ - host = this->ike_sa->get_my_host(this->ike_sa); - this->new_sa->set_my_host(this->new_sa, host->clone(host)); - host = this->ike_sa->get_other_host(this->ike_sa); - this->new_sa->set_other_host(this->new_sa, host->clone(host)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - this->new_sa->set_state(this->new_sa, IKE_REKEYING); - if (this->new_sa->delete(this->new_sa) == DESTROY_ME) - { - this->new_sa->destroy(this->new_sa); - } - else - { - charon->ike_sa_manager->checkin( - charon->ike_sa_manager, this->new_sa); - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - } - this->new_sa = NULL; - establish_new(other); - return SUCCESS; - } - } - /* set threads active IKE_SA after checkin */ - charon->bus->set_sa(charon->bus, this->ike_sa); - } - - establish_new(this); - - /* rekeying successful, delete the IKE_SA using a subtask */ - this->ike_delete = ike_delete_create(this->ike_sa, TRUE); - this->public.task.build = _build_i_delete; - this->public.task.process = _process_i_delete; - - return NEED_MORE; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_rekey_t *this) -{ - return IKE_REKEY; -} - -METHOD(ike_rekey_t, collide, void, - private_ike_rekey_t* this, task_t *other) -{ - DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, IKE_REKEY, - task_type_names, other->get_type(other)); - DESTROY_IF(this->collision); - this->collision = other; -} - -METHOD(task_t, migrate, void, - private_ike_rekey_t *this, ike_sa_t *ike_sa) -{ - if (this->ike_init) - { - this->ike_init->task.destroy(&this->ike_init->task); - } - if (this->ike_delete) - { - this->ike_delete->task.destroy(&this->ike_delete->task); - } - DESTROY_IF(this->new_sa); - DESTROY_IF(this->collision); - - this->collision = NULL; - this->ike_sa = ike_sa; - this->new_sa = NULL; - this->ike_init = NULL; - this->ike_delete = NULL; -} - -METHOD(task_t, destroy, void, - private_ike_rekey_t *this) -{ - if (this->ike_init) - { - this->ike_init->task.destroy(&this->ike_init->task); - } - if (this->ike_delete) - { - this->ike_delete->task.destroy(&this->ike_delete->task); - } - DESTROY_IF(this->new_sa); - DESTROY_IF(this->collision); - free(this); -} - -/* - * Described in header. - */ -ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_rekey_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .build = _build_r, - .process = _process_r, - .migrate = _migrate, - .destroy = _destroy, - }, - .collide = _collide, - }, - .ike_sa = ike_sa, - .initiator = initiator, - ); - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/ike_rekey.h b/src/libcharon/sa/tasks/ike_rekey.h deleted file mode 100644 index 1c9550768..000000000 --- a/src/libcharon/sa/tasks/ike_rekey.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_rekey ike_rekey - * @{ @ingroup tasks - */ - -#ifndef IKE_REKEY_H_ -#define IKE_REKEY_H_ - -typedef struct ike_rekey_t ike_rekey_t; - -#include -#include -#include - -/** - * Task of type IKE_REKEY, rekey an established IKE_SA. - */ -struct ike_rekey_t { - - /** - * Implements the task_t interface - */ - task_t task; - - /** - * Register a rekeying task which collides with this one. - * - * If two peers initiate rekeying at the same time, the collision must - * be handled gracefully. The task manager is aware of what exchanges - * are going on and notifies the outgoing task by passing the incoming. - * - * @param other incoming task - */ - void (*collide)(ike_rekey_t* this, task_t *other); -}; - -/** - * Create a new IKE_REKEY task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE for initiator, FALSE for responder - * @return IKE_REKEY task to handle by the task_manager - */ -ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_REKEY_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c deleted file mode 100644 index 1c14ee06b..000000000 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "ike_vendor.h" - -#include -#include - -typedef struct private_ike_vendor_t private_ike_vendor_t; - -/** - * Private data of an ike_vendor_t object. - */ -struct private_ike_vendor_t { - - /** - * Public ike_vendor_t interface. - */ - ike_vendor_t public; - - /** - * Associated IKE_SA - */ - ike_sa_t *ike_sa; - - /** - * Are we the inititator of this task - */ - bool initiator; -}; - -/** - * strongSwan specific vendor ID without version, MD5("strongSwan") - */ -static chunk_t strongswan_vid = chunk_from_chars( - 0x88,0x2f,0xe5,0x6d,0x6f,0xd2,0x0d,0xbc, - 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb -); - -METHOD(task_t, build, status_t, - private_ike_vendor_t *this, message_t *message) -{ - if (lib->settings->get_bool(lib->settings, - "charon.send_vendor_id", FALSE)) - { - vendor_id_payload_t *vid; - - vid = vendor_id_payload_create_data(chunk_clone(strongswan_vid)); - message->add_payload(message, &vid->payload_interface); - } - - return this->initiator ? NEED_MORE : SUCCESS; -} - -METHOD(task_t, process, status_t, - private_ike_vendor_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == VENDOR_ID) - { - vendor_id_payload_t *vid; - chunk_t data; - - vid = (vendor_id_payload_t*)payload; - data = vid->get_data(vid); - - if (chunk_equals(data, strongswan_vid)) - { - DBG1(DBG_IKE, "received strongSwan vendor id"); - this->ike_sa->enable_extension(this->ike_sa, EXT_STRONGSWAN); - } - else - { - DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); - } - } - } - enumerator->destroy(enumerator); - - return this->initiator ? SUCCESS : NEED_MORE; -} - -METHOD(task_t, migrate, void, - private_ike_vendor_t *this, ike_sa_t *ike_sa) -{ - this->ike_sa = ike_sa; -} - -METHOD(task_t, get_type, task_type_t, - private_ike_vendor_t *this) -{ - return IKE_VENDOR; -} - -METHOD(task_t, destroy, void, - private_ike_vendor_t *this) -{ - free(this); -} - -/** - * See header - */ -ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator) -{ - private_ike_vendor_t *this; - - INIT(this, - .public = { - .task = { - .build = _build, - .process = _process, - .migrate = _migrate, - .get_type = _get_type, - .destroy = _destroy, - }, - }, - .initiator = initiator, - .ike_sa = ike_sa, - ); - - return &this->public; -} - diff --git a/src/libcharon/sa/tasks/ike_vendor.h b/src/libcharon/sa/tasks/ike_vendor.h deleted file mode 100644 index 6c353c447..000000000 --- a/src/libcharon/sa/tasks/ike_vendor.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup ike_vendor ike_vendor - * @{ @ingroup tasks - */ - -#ifndef IKE_VENDOR_H_ -#define IKE_VENDOR_H_ - -typedef struct ike_vendor_t ike_vendor_t; - -#include -#include -#include - -/** - * Vendor ID processing task. - */ -struct ike_vendor_t { - - /** - * Implements task interface. - */ - task_t task; -}; - -/** - * Create a ike_vendor instance. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE if task is the original initiator - */ -ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** IKE_VENDOR_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c deleted file mode 100644 index 0d7383141..000000000 --- a/src/libcharon/sa/tasks/task.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "task.h" - -#ifdef ME -ENUM(task_type_names, IKE_INIT, CHILD_REKEY, - "IKE_INIT", - "IKE_NATD", - "IKE_MOBIKE", - "IKE_AUTHENTICATE", - "IKE_AUTH_LIFETIME", - "IKE_CERT_PRE", - "IKE_CERT_POST", - "IKE_CONFIG", - "IKE_REKEY", - "IKE_REAUTH", - "IKE_DELETE", - "IKE_DPD", - "IKE_VENDOR", - "IKE_ME", - "CHILD_CREATE", - "CHILD_DELETE", - "CHILD_REKEY", -); -#else -ENUM(task_type_names, IKE_INIT, CHILD_REKEY, - "IKE_INIT", - "IKE_NATD", - "IKE_MOBIKE", - "IKE_AUTHENTICATE", - "IKE_AUTH_LIFETIME", - "IKE_CERT_PRE", - "IKE_CERT_POST", - "IKE_CONFIG", - "IKE_REKEY", - "IKE_REAUTH", - "IKE_DELETE", - "IKE_DPD", - "IKE_VENDOR", - "CHILD_CREATE", - "CHILD_DELETE", - "CHILD_REKEY", -); -#endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h deleted file mode 100644 index d57085954..000000000 --- a/src/libcharon/sa/tasks/task.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup task task - * @{ @ingroup tasks - */ - -#ifndef TASK_H_ -#define TASK_H_ - -typedef enum task_type_t task_type_t; -typedef struct task_t task_t; - -#include -#include -#include - -/** - * Different kinds of tasks. - */ -enum task_type_t { - /** establish an unauthenticated IKE_SA */ - IKE_INIT, - /** detect NAT situation */ - IKE_NATD, - /** handle MOBIKE stuff */ - IKE_MOBIKE, - /** authenticate the initiated IKE_SA */ - IKE_AUTHENTICATE, - /** AUTH_LIFETIME negotiation, RFC4478 */ - IKE_AUTH_LIFETIME, - /** certificate processing before authentication (certreqs, cert parsing) */ - IKE_CERT_PRE, - /** certificate processing after authentication (certs payload generation) */ - IKE_CERT_POST, - /** Configuration payloads, virtual IP and such */ - IKE_CONFIG, - /** rekey an IKE_SA */ - IKE_REKEY, - /** reestablish a complete IKE_SA */ - IKE_REAUTH, - /** delete an IKE_SA */ - IKE_DELETE, - /** liveness check */ - IKE_DPD, - /** Vendor ID processing */ - IKE_VENDOR, -#ifdef ME - /** handle ME stuff */ - IKE_ME, -#endif /* ME */ - /** establish a CHILD_SA within an IKE_SA */ - CHILD_CREATE, - /** delete an established CHILD_SA */ - CHILD_DELETE, - /** rekey an CHILD_SA */ - CHILD_REKEY, -}; - -/** - * enum names for task_type_t. - */ -extern enum_name_t *task_type_names; - -/** - * Interface for a task, an operation handled within exchanges. - * - * A task is an elemantary operation. It may be handled by a single or by - * multiple exchanges. An exchange may even complete multiple tasks. - * A task has a build() and an process() operation. The build() operation - * creates payloads and adds it to the message. The process() operation - * inspects a message and handles its payloads. An initiator of an exchange - * first calls build() to build the request, and processes the response message - * with the process() method. - * A responder does the opposite; it calls process() first to handle an incoming - * request and secondly calls build() to build an appropriate response. - * Both methods return either SUCCESS, NEED_MORE or FAILED. A SUCCESS indicates - * that the task completed, even when the task completed unsuccessfully. The - * manager then removes the task from the list. A NEED_MORE is returned when - * the task needs further build()/process() calls to complete, the manager - * leaves the taks in the queue. A returned FAILED indicates a critical failure. - * The manager closes the IKE_SA whenever a task returns FAILED. - */ -struct task_t { - - /** - * Build a request or response message for this task. - * - * @param message message to add payloads to - * @return - * - FAILED if a critical error occurred - * - DESTROY_ME if IKE_SA has been properly deleted - * - NEED_MORE if another call to build/process needed - * - SUCCESS if task completed - */ - status_t (*build) (task_t *this, message_t *message); - - /** - * Process a request or response message for this task. - * - * @param message message to read payloads from - * @return - * - FAILED if a critical error occurred - * - DESTROY_ME if IKE_SA has been properly deleted - * - NEED_MORE if another call to build/process needed - * - SUCCESS if task completed - */ - status_t (*process) (task_t *this, message_t *message); - - /** - * Get the type of the task implementation. - */ - task_type_t (*get_type) (task_t *this); - - /** - * Migrate a task to a new IKE_SA. - * - * After migrating a task, it goes back to a state where it can be - * used again to initate an exchange. This is useful when a task - * has to get migrated to a new IKE_SA. - * A special usage is when a INVALID_KE_PAYLOAD is received. A call - * to reset resets the task, but uses another DH group for the next - * try. - * The ike_sa is the new IKE_SA this task belongs to and operates on. - * - * @param ike_sa new IKE_SA this task works for - */ - void (*migrate) (task_t *this, ike_sa_t *ike_sa); - - /** - * Destroys a task_t object. - */ - void (*destroy) (task_t *this); -}; - -#endif /** TASK_H_ @}*/ diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index 86d9f4c22..fdcfa0a20 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -98,7 +98,7 @@ METHOD(trap_manager_t, install, u_int32_t, ike_cfg_t *ike_cfg; child_sa_t *child_sa; host_t *me, *other; - linked_list_t *my_ts, *other_ts; + linked_list_t *my_ts, *other_ts, *list; enumerator_t *enumerator; bool found = FALSE; status_t status; @@ -127,14 +127,14 @@ METHOD(trap_manager_t, install, u_int32_t, /* try to resolve addresses */ ike_cfg = peer->get_ike_cfg(peer); - other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), + other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg, NULL), 0, ike_cfg->get_other_port(ike_cfg)); if (!other || other->is_anyaddr(other)) { DBG1(DBG_CFG, "installing trap failed, remote address unknown"); return 0; } - me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg), + me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg, NULL), other->get_family(other), ike_cfg->get_my_port(ike_cfg)); if (!me || me->is_anyaddr(me)) { @@ -152,10 +152,14 @@ METHOD(trap_manager_t, install, u_int32_t, /* create and route CHILD_SA */ child_sa = child_sa_create(me, other, child, 0, FALSE); - my_ts = child->get_traffic_selectors(child, TRUE, NULL, me); - other_ts = child->get_traffic_selectors(child, FALSE, NULL, other); - me->destroy(me); - other->destroy(other); + + list = linked_list_create_with_items(me, NULL); + my_ts = child->get_traffic_selectors(child, TRUE, NULL, list); + list->destroy_offset(list, offsetof(host_t, destroy)); + + list = linked_list_create_with_items(other, NULL); + other_ts = child->get_traffic_selectors(child, FALSE, NULL, list); + list->destroy_offset(list, offsetof(host_t, destroy)); /* while we don't know the finally negotiated protocol (ESP|AH), we * could iterate all proposals for a best guess (TODO). But as we @@ -284,26 +288,34 @@ METHOD(trap_manager_t, acquire, void, ike_sa = charon->ike_sa_manager->checkout_by_config( charon->ike_sa_manager, peer); - if (ike_sa->get_peer_cfg(ike_sa) == NULL) - { - ike_sa->set_peer_cfg(ike_sa, peer); - } - if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + if (ike_sa) { - /* make sure the entry is still there */ - this->lock->read_lock(this->lock); - if (this->traps->find_first(this->traps, NULL, - (void**)&found) == SUCCESS) + if (ike_sa->get_peer_cfg(ike_sa) == NULL) { - found->ike_sa = ike_sa; + ike_sa->set_peer_cfg(ike_sa, peer); + } + if (ike_sa->get_version(ike_sa) == IKEV1) + { /* in IKEv1, don't prepend the acquiring packet TS, as we only + * have a single TS that we can establish in a Quick Mode. */ + src = dst = NULL; + } + if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + { + /* make sure the entry is still there */ + this->lock->read_lock(this->lock); + if (this->traps->find_first(this->traps, NULL, + (void**)&found) == SUCCESS) + { + found->ike_sa = ike_sa; + } + this->lock->unlock(this->lock); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); } - this->lock->unlock(this->lock); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - else - { - charon->ike_sa_manager->checkin_and_destroy( - charon->ike_sa_manager, ike_sa); } peer->destroy(peer); } diff --git a/src/libcharon/sa/xauth/xauth_manager.c b/src/libcharon/sa/xauth/xauth_manager.c new file mode 100644 index 000000000..432c9c0ab --- /dev/null +++ b/src/libcharon/sa/xauth/xauth_manager.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_manager.h" + +#include +#include + +typedef struct private_xauth_manager_t private_xauth_manager_t; +typedef struct xauth_entry_t xauth_entry_t; + +/** + * XAuth constructor entry + */ +struct xauth_entry_t { + + /** + * Xauth backend name + */ + char *name; + + /** + * Role of the method, XAUTH_SERVER or XAUTH_PEER + */ + xauth_role_t role; + + /** + * constructor function to create instance + */ + xauth_constructor_t constructor; +}; + +/** + * private data of xauth_manager + */ +struct private_xauth_manager_t { + + /** + * public functions + */ + xauth_manager_t public; + + /** + * list of eap_entry_t's + */ + linked_list_t *methods; + + /** + * rwlock to lock methods + */ + rwlock_t *lock; +}; + +METHOD(xauth_manager_t, add_method, void, + private_xauth_manager_t *this, char *name, xauth_role_t role, + xauth_constructor_t constructor) +{ + xauth_entry_t *entry; + + INIT(entry, + .name = name, + .role = role, + .constructor = constructor, + ); + + this->lock->write_lock(this->lock); + this->methods->insert_last(this->methods, entry); + this->lock->unlock(this->lock); +} + +METHOD(xauth_manager_t, remove_method, void, + private_xauth_manager_t *this, xauth_constructor_t constructor) +{ + enumerator_t *enumerator; + xauth_entry_t *entry; + + this->lock->write_lock(this->lock); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (constructor == entry->constructor) + { + this->methods->remove_at(this->methods, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + +METHOD(xauth_manager_t, create_instance, xauth_method_t*, + private_xauth_manager_t *this, char *name, xauth_role_t role, + identification_t *server, identification_t *peer) +{ + enumerator_t *enumerator; + xauth_entry_t *entry; + xauth_method_t *method = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->methods->create_enumerator(this->methods); + while (enumerator->enumerate(enumerator, &entry)) + { + if (role == entry->role && + (!name || streq(name, entry->name))) + { + method = entry->constructor(server, peer); + if (method) + { + break; + } + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return method; +} + +METHOD(xauth_manager_t, destroy, void, + private_xauth_manager_t *this) +{ + this->methods->destroy_function(this->methods, free); + this->lock->destroy(this->lock); + free(this); +} + +/* + * See header + */ +xauth_manager_t *xauth_manager_create() +{ + private_xauth_manager_t *this; + + INIT(this, + .public = { + .add_method = _add_method, + .remove_method = _remove_method, + .create_instance = _create_instance, + .destroy = _destroy, + }, + .methods = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/xauth/xauth_manager.h b/src/libcharon/sa/xauth/xauth_manager.h new file mode 100644 index 000000000..929d5de8f --- /dev/null +++ b/src/libcharon/sa/xauth/xauth_manager.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_manager xauth_manager + * @{ @ingroup xauth + */ + +#ifndef XAUTH_MANAGER_H_ +#define XAUTH_MANAGER_H_ + +#include + +typedef struct xauth_manager_t xauth_manager_t; + +/** + * The XAuth manager manages all XAuth implementations and creates instances. + * + * A plugin registers it's implemented XAuth method at the manager by + * providing type and a contructor function. The manager then instanciates + * xauth_method_t instances through the provided constructor to handle + * XAuth authentication. + */ +struct xauth_manager_t { + + /** + * Register a XAuth method implementation. + * + * @param name backend name to register + * @param role XAUTH_SERVER or XAUTH_PEER + * @param constructor constructor function, returns an xauth_method_t + */ + void (*add_method)(xauth_manager_t *this, char *name, + xauth_role_t role, xauth_constructor_t constructor); + + /** + * Unregister a XAuth method implementation using it's constructor. + * + * @param constructor constructor function, as added in add_method + */ + void (*remove_method)(xauth_manager_t *this, xauth_constructor_t constructor); + + /** + * Create a new XAuth method instance. + * + * @param name backend name, as it was registered with + * @param role XAUTH_SERVER or XAUTH_PEER + * @param server identity of the server + * @param peer identity of the peer (client) + * @return XAUTH method instance, NULL if no constructor found + */ + xauth_method_t* (*create_instance)(xauth_manager_t *this, + char *name, xauth_role_t role, + identification_t *server, identification_t *peer); + + /** + * Destroy a eap_manager instance. + */ + void (*destroy)(xauth_manager_t *this); +}; + +/** + * Create a eap_manager instance. + */ +xauth_manager_t *xauth_manager_create(); + +#endif /** XAUTH_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/xauth/xauth_method.c b/src/libcharon/sa/xauth/xauth_method.c new file mode 100644 index 000000000..838822d1e --- /dev/null +++ b/src/libcharon/sa/xauth/xauth_method.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_method.h" + +#include + +ENUM(xauth_role_names, XAUTH_SERVER, XAUTH_PEER, + "XAUTH_SERVER", + "XAUTH_PEER", +); + +/** + * See header + */ +bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data) +{ + if (reg) + { + charon->xauth->add_method(charon->xauth, feature->arg.xauth, + feature->type == FEATURE_XAUTH_SERVER ? XAUTH_SERVER : XAUTH_PEER, + (xauth_constructor_t)data); + } + else + { + charon->xauth->remove_method(charon->xauth, (xauth_constructor_t)data); + } + return TRUE; +} diff --git a/src/libcharon/sa/xauth/xauth_method.h b/src/libcharon/sa/xauth/xauth_method.h new file mode 100644 index 000000000..9f6067dbf --- /dev/null +++ b/src/libcharon/sa/xauth/xauth_method.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2006 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_method xauth_method + * @{ @ingroup xauth + */ + +#ifndef XAUTH_METHOD_H_ +#define XAUTH_METHOD_H_ + +typedef struct xauth_method_t xauth_method_t; +typedef enum xauth_role_t xauth_role_t; + +#include +#include +#include +#include + +/** + * Role of an xauth_method, SERVER or PEER (client) + */ +enum xauth_role_t { + XAUTH_SERVER, + XAUTH_PEER, +}; + +/** + * enum names for xauth_role_t. + */ +extern enum_name_t *xauth_role_names; + +/** + * Interface of an XAuth method for server and client side. + * + * An XAuth method initiates an XAuth exchange and processes requests and + * responses. An XAuth method may need multiple exchanges before succeeding. + * Sending of XAUTH(STATUS) message is done by the framework, not a method. + */ +struct xauth_method_t { + + /** + * Initiate the XAuth exchange. + * + * initiate() is only useable for server implementations, as clients only + * reply to server requests. + * A cp_payload is created in "out" if result is NEED_MORE. + * + * @param out cp_payload to send to the client + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if unable to create XAuth request payload + */ + status_t (*initiate) (xauth_method_t *this, cp_payload_t **out); + + /** + * Process a received XAuth message. + * + * A cp_payload is created in "out" if result is NEED_MORE. + * + * @param in cp_payload response received + * @param out created cp_payload to send + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if XAuth method failed + * - SUCCESS, if XAuth method succeeded + */ + status_t (*process) (xauth_method_t *this, cp_payload_t *in, + cp_payload_t **out); + + /** + * Get the XAuth username received as XAuth initiator. + * + * @return used XAuth username, pointer to internal data + */ + identification_t* (*get_identity)(xauth_method_t *this); + + /** + * Destroys a eap_method_t object. + */ + void (*destroy) (xauth_method_t *this); +}; + +/** + * Constructor definition for a pluggable XAuth method. + * + * Each XAuth module must define a constructor function which will return + * an initialized object with the methods defined in xauth_method_t. + * Constructors for server and peers are identical, to support both roles + * of a XAuth method, a plugin needs register two constructors in the + * xauth_manager_t. + * + * @param server ID of the server to use for credential lookup + * @param peer ID of the peer to use for credential lookup + * @return implementation of the eap_method_t interface + */ +typedef xauth_method_t *(*xauth_constructor_t)(identification_t *server, + identification_t *peer); + +/** + * Helper function to (un-)register XAuth methods from plugin features. + * + * This function is a plugin_feature_callback_t and can be used with the + * PLUGIN_CALLBACK macro to register a XAuth method constructor. + * + * @param plugin plugin registering the XAuth method constructor + * @param feature associated plugin feature + * @param reg TRUE to register, FALSE to unregister. + * @param data data passed to callback, an xauth_constructor_t + */ +bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data); + +#endif /** XAUTH_METHOD_H_ @}*/ diff --git a/src/libfast/Makefile.am b/src/libfast/Makefile.am index 35d102109..df5b650ce 100644 --- a/src/libfast/Makefile.am +++ b/src/libfast/Makefile.am @@ -1,7 +1,14 @@ ipseclib_LTLIBRARIES = libfast.la -libfast_la_SOURCES = context.h dispatcher.c request.h session.h \ - controller.h dispatcher.h request.c session.c filter.h smtp.c smtp.h +libfast_la_SOURCES = \ + dispatcher.c request.c session.c smtp.c + +if USE_DEV_HEADERS +fast_includedir = ${dev_headers}/fast +nobase_fast_include_HEADERS = \ + context.h controller.h dispatcher.h filter.h request.h session.h smtp.h +endif + libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ -lfcgi $(clearsilver_LIBS) $(PTHREADLIB) INCLUDES = -I$(top_srcdir)/src/libstrongswan -I/usr/include/ClearSilver diff --git a/src/libfast/Makefile.in b/src/libfast/Makefile.in index abb721758..78341c7e7 100644 --- a/src/libfast/Makefile.in +++ b/src/libfast/Makefile.in @@ -15,6 +15,7 @@ @SET_MAKE@ + VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ @@ -35,7 +36,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/libfast -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +DIST_COMMON = $(am__nobase_fast_include_HEADERS_DIST) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ $(top_srcdir)/m4/config/ltoptions.m4 \ @@ -49,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -72,7 +75,8 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(ipseclibdir)" +am__installdirs = "$(DESTDIR)$(ipseclibdir)" \ + "$(DESTDIR)$(fast_includedir)" LTLIBRARIES = $(ipseclib_LTLIBRARIES) am__DEPENDENCIES_1 = libfast_la_DEPENDENCIES = \ @@ -80,7 +84,7 @@ libfast_la_DEPENDENCIES = \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libfast_la_OBJECTS = dispatcher.lo request.lo session.lo smtp.lo libfast_la_OBJECTS = $(am_libfast_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -95,6 +99,9 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libfast_la_SOURCES) DIST_SOURCES = $(libfast_la_SOURCES) +am__nobase_fast_include_HEADERS_DIST = context.h controller.h \ + dispatcher.h filter.h request.h session.h smtp.h +HEADERS = $(nobase_fast_include_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -106,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -200,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -221,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -241,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -250,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -279,8 +291,12 @@ urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ ipseclib_LTLIBRARIES = libfast.la -libfast_la_SOURCES = context.h dispatcher.c request.h session.h \ - controller.h dispatcher.h request.c session.c filter.h smtp.c smtp.h +libfast_la_SOURCES = \ + dispatcher.c request.c session.c smtp.c + +@USE_DEV_HEADERS_TRUE@fast_includedir = ${dev_headers}/fast +@USE_DEV_HEADERS_TRUE@nobase_fast_include_HEADERS = \ +@USE_DEV_HEADERS_TRUE@ context.h controller.h dispatcher.h filter.h request.h session.h smtp.h libfast_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \ -lfcgi $(clearsilver_LIBS) $(PTHREADLIB) @@ -392,6 +408,29 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs +install-nobase_fast_includeHEADERS: $(nobase_fast_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(fast_includedir)" || $(MKDIR_P) "$(DESTDIR)$(fast_includedir)" + @list='$(nobase_fast_include_HEADERS)'; test -n "$(fast_includedir)" || list=; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo "$(MKDIR_P) '$(DESTDIR)$(fast_includedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(fast_includedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(fast_includedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(fast_includedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_fast_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_fast_include_HEADERS)'; test -n "$(fast_includedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(fast_includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(fast_includedir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -477,9 +516,9 @@ distdir: $(DISTFILES) done check-am: all-am check: check-am -all-am: Makefile $(LTLIBRARIES) +all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: - for dir in "$(DESTDIR)$(ipseclibdir)"; do \ + for dir in "$(DESTDIR)$(ipseclibdir)" "$(DESTDIR)$(fast_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -530,7 +569,8 @@ info: info-am info-am: -install-data-am: install-ipseclibLTLIBRARIES +install-data-am: install-ipseclibLTLIBRARIES \ + install-nobase_fast_includeHEADERS install-dvi: install-dvi-am @@ -576,7 +616,8 @@ ps: ps-am ps-am: -uninstall-am: uninstall-ipseclibLTLIBRARIES +uninstall-am: uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_fast_includeHEADERS .MAKE: install-am install-strip @@ -587,12 +628,14 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ - install-ipseclibLTLIBRARIES install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ + install-ipseclibLTLIBRARIES install-man \ + install-nobase_fast_includeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES + tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_fast_includeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/src/libfast/dispatcher.c b/src/libfast/dispatcher.c index e5fca7074..63c872e35 100644 --- a/src/libfast/dispatcher.c +++ b/src/libfast/dispatcher.c @@ -179,10 +179,16 @@ static session_entry_t *session_entry_create(private_dispatcher_t *this, char *host) { session_entry_t *entry; + session_t *session; + session = load_session(this); + if (!session) + { + return NULL; + } INIT(entry, .cond = condvar_create(CONDVAR_TYPE_DEFAULT), - .session = load_session(this), + .session = session, .host = strdup(host), .used = time_monotonic(NULL), ); @@ -324,6 +330,12 @@ static void dispatch(private_dispatcher_t *this) else { /* create a new session if not found */ found = session_entry_create(this, request->get_host(request)); + if (!found) + { + request->destroy(request); + this->mutex->unlock(this->mutex); + continue; + } sid = found->session->get_sid(found->session); this->sessions->put(this->sessions, sid, found); } diff --git a/src/libfast/request.c b/src/libfast/request.c index 3acd831b2..6ca474037 100644 --- a/src/libfast/request.c +++ b/src/libfast/request.c @@ -22,6 +22,11 @@ #include #include #include +#include +#include +#include +#include + #include #include @@ -275,6 +280,60 @@ METHOD(request_t, serve, void, FCGX_PutStr(chunk.ptr, chunk.len, this->req.out); } +METHOD(request_t, sendfile, bool, + private_request_t *this, char *path, char *mime) +{ + struct stat sb; + chunk_t data; + void *addr; + int fd, written; + char buf[24]; + + fd = open(path, O_RDONLY); + if (fd == -1) + { + return FALSE; + } + if (fstat(fd, &sb) == -1) + { + close(fd); + return FALSE; + } + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) + { + close(fd); + return FALSE; + } + + /* FCGX does not like large integers, print to a buffer using libc */ + snprintf(buf, sizeof(buf), "%lld", (int64_t)sb.st_size); + FCGX_FPrintF(this->req.out, "Content-Length: %s\n", buf); + if (mime) + { + FCGX_FPrintF(this->req.out, "Content-Type: %s\n", mime); + } + FCGX_FPrintF(this->req.out, "\n"); + + data = chunk_create(addr, sb.st_size); + + while (data.len) + { + written = FCGX_PutStr(data.ptr, data.len, this->req.out); + if (written == -1) + { + munmap(addr, sb.st_size); + close(fd); + return FALSE; + } + data = chunk_skip(data, written); + } + + munmap(addr, sb.st_size); + close(fd); + return TRUE; +} + METHOD(request_t, render, void, private_request_t *this, char *template) { @@ -380,6 +439,7 @@ request_t *request_create(int fd, bool debug) .render = _render, .streamf = _streamf, .serve = _serve, + .sendfile = _sendfile, .set = _set, .setf = _setf, .get_ref = _get_ref, diff --git a/src/libfast/request.h b/src/libfast/request.h index c9c1f13e2..63a465bb8 100644 --- a/src/libfast/request.h +++ b/src/libfast/request.h @@ -184,6 +184,15 @@ struct request_t { */ void (*serve)(request_t *this, char *headers, chunk_t chunk); + /** + * Send a file from the file system. + * + * @param path path to file to serve + * @param mime mime type of file to send, or NULL + * @return TRUE if file served successfully + */ + bool (*sendfile)(request_t *this, char *path, char *mime); + /** * Increase the reference count to the stream. * diff --git a/src/libfast/session.c b/src/libfast/session.c index 1d9ed0107..cf14dbeb6 100644 --- a/src/libfast/session.c +++ b/src/libfast/session.c @@ -78,20 +78,24 @@ METHOD(session_t, add_filter, void, /** * Create a session ID and a cookie */ -static void create_sid(private_session_t *this) +static bool create_sid(private_session_t *this) { char buf[COOKIE_LEN]; rng_t *rng; - memset(buf, 0, sizeof(buf)); - memset(this->sid, 0, sizeof(this->sid)); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (rng) + if (!rng) + { + return FALSE; + } + if (!rng->get_bytes(rng, sizeof(buf), buf)) { - rng->get_bytes(rng, sizeof(buf), buf); rng->destroy(rng); + return FALSE; } + rng->destroy(rng); chunk_to_hex(chunk_create(buf, sizeof(buf)), this->sid, FALSE); + return TRUE; } /** @@ -212,7 +216,11 @@ session_t *session_create(context_t *context) .filters = linked_list_create(), .context = context, ); - create_sid(this); + if (!create_sid(this)) + { + destroy(this); + return NULL; + } return &this->public; } diff --git a/src/libfast/session.h b/src/libfast/session.h index f60fa9ef2..acbab8964 100644 --- a/src/libfast/session.h +++ b/src/libfast/session.h @@ -70,6 +70,7 @@ struct session_t { * Create a session new session. * * @param context user defined session context instance + * @return client session, NULL on error */ session_t *session_create(context_t *context); diff --git a/src/libfast/smtp.c b/src/libfast/smtp.c index 4118c74a6..1375c2944 100644 --- a/src/libfast/smtp.c +++ b/src/libfast/smtp.c @@ -136,7 +136,13 @@ METHOD(smtp_t, destroy, void, smtp_t *smtp_create() { private_smtp_t *this; - struct sockaddr_in addr; + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(25), + .sin_addr = { + .s_addr = htonl(INADDR_LOOPBACK), + }, + }; int s; INIT(this, @@ -153,9 +159,6 @@ smtp_t *smtp_create() free(this); return NULL; } - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(25); if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) { DBG1(DBG_LIB, "connecting to SMTP server failed: %s", strerror(errno)); diff --git a/src/libfreeswan/Android.mk b/src/libfreeswan/Android.mk deleted file mode 100644 index a834d4846..000000000 --- a/src/libfreeswan/Android.mk +++ /dev/null @@ -1,38 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# copy-n-paste from Makefile.am -LOCAL_SRC_FILES := \ -addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \ -atosubnet.c atoul.c copyright.c datatot.c freeswan.h \ -goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipsec_param.h \ -pfkey_v2_build.c pfkey_v2_debug.c \ -pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c rangetoa.c \ -pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c \ -satot.c subnetof.c subnettoa.c subnettot.c \ -subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \ -ultoa.c ultot.c - -# build libfreeswan ------------------------------------------------------------ - -LOCAL_C_INCLUDES += \ - $(libvstr_PATH) \ - $(strongswan_PATH)/src/include \ - $(strongswan_PATH)/src/libstrongswan \ - $(strongswan_PATH)/src/libhydra \ - $(strongswan_PATH)/src/pluto - -LOCAL_CFLAGS := $(strongswan_CFLAGS) - -LOCAL_MODULE := libfreeswan - -LOCAL_MODULE_TAGS := optional - -LOCAL_ARM_MODE := arm - -LOCAL_PRELINK_MODULE := false - -LOCAL_SHARED_LIBRARIES += libstrongswan - -include $(BUILD_SHARED_LIBRARY) - diff --git a/src/libfreeswan/Makefile.am b/src/libfreeswan/Makefile.am deleted file mode 100644 index b38343d34..000000000 --- a/src/libfreeswan/Makefile.am +++ /dev/null @@ -1,22 +0,0 @@ -noinst_LIBRARIES = libfreeswan.a -libfreeswan_a_SOURCES = \ -addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \ -atosubnet.c atoul.c copyright.c datatot.c freeswan.h \ -goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipsec_param.h \ -pfkey_v2_build.c pfkey_v2_debug.c \ -pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c rangetoa.c \ -pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c \ -satot.c subnetof.c subnettoa.c subnettot.c \ -subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \ -ultoa.c ultot.c - -INCLUDES = \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/pluto - -dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atoul.3 goodmask.3 initaddr.3 initsubnet.3 \ - portof.3 rangetosubnet.3 sameaddr.3 subnetof.3 \ - ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 - -EXTRA_DIST = Android.mk diff --git a/src/libfreeswan/Makefile.in b/src/libfreeswan/Makefile.in deleted file mode 100644 index b6ee06630..000000000 --- a/src/libfreeswan/Makefile.in +++ /dev/null @@ -1,682 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/libfreeswan -DIST_COMMON = $(dist_man3_MANS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -LIBRARIES = $(noinst_LIBRARIES) -ARFLAGS = cru -libfreeswan_a_AR = $(AR) $(ARFLAGS) -libfreeswan_a_LIBADD = -am_libfreeswan_a_OBJECTS = addrtoa.$(OBJEXT) addrtot.$(OBJEXT) \ - addrtypeof.$(OBJEXT) anyaddr.$(OBJEXT) atoaddr.$(OBJEXT) \ - atoasr.$(OBJEXT) atosubnet.$(OBJEXT) atoul.$(OBJEXT) \ - copyright.$(OBJEXT) datatot.$(OBJEXT) goodmask.$(OBJEXT) \ - initaddr.$(OBJEXT) initsaid.$(OBJEXT) initsubnet.$(OBJEXT) \ - pfkey_v2_build.$(OBJEXT) pfkey_v2_debug.$(OBJEXT) \ - pfkey_v2_ext_bits.$(OBJEXT) pfkey_v2_parse.$(OBJEXT) \ - portof.$(OBJEXT) rangetoa.$(OBJEXT) rangetosubnet.$(OBJEXT) \ - sameaddr.$(OBJEXT) satot.$(OBJEXT) subnetof.$(OBJEXT) \ - subnettoa.$(OBJEXT) subnettot.$(OBJEXT) subnettypeof.$(OBJEXT) \ - ttoaddr.$(OBJEXT) ttodata.$(OBJEXT) ttoprotoport.$(OBJEXT) \ - ttosa.$(OBJEXT) ttosubnet.$(OBJEXT) ttoul.$(OBJEXT) \ - ultoa.$(OBJEXT) ultot.$(OBJEXT) -libfreeswan_a_OBJECTS = $(am_libfreeswan_a_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libfreeswan_a_SOURCES) -DIST_SOURCES = $(libfreeswan_a_SOURCES) -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -man3dir = $(mandir)/man3 -am__installdirs = "$(DESTDIR)$(man3dir)" -NROFF = nroff -MANS = $(dist_man3_MANS) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -noinst_LIBRARIES = libfreeswan.a -libfreeswan_a_SOURCES = \ -addrtoa.c addrtot.c addrtypeof.c anyaddr.c atoaddr.c atoasr.c \ -atosubnet.c atoul.c copyright.c datatot.c freeswan.h \ -goodmask.c initaddr.c initsaid.c initsubnet.c internal.h ipsec_param.h \ -pfkey_v2_build.c pfkey_v2_debug.c \ -pfkey_v2_ext_bits.c pfkey_v2_parse.c portof.c rangetoa.c \ -pfkey.h pfkeyv2.h rangetosubnet.c sameaddr.c \ -satot.c subnetof.c subnettoa.c subnettot.c \ -subnettypeof.c ttoaddr.c ttodata.c ttoprotoport.c ttosa.c ttosubnet.c ttoul.c \ -ultoa.c ultot.c - -INCLUDES = \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/pluto - -dist_man3_MANS = anyaddr.3 atoaddr.3 atoasr.3 atoul.3 goodmask.3 initaddr.3 initsubnet.3 \ - portof.3 rangetosubnet.3 sameaddr.3 subnetof.3 \ - ttoaddr.3 ttodata.3 ttosa.3 ttoul.3 - -EXTRA_DIST = Android.mk -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libfreeswan/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/libfreeswan/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -clean-noinstLIBRARIES: - -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) -libfreeswan.a: $(libfreeswan_a_OBJECTS) $(libfreeswan_a_DEPENDENCIES) - -rm -f libfreeswan.a - $(libfreeswan_a_AR) libfreeswan.a $(libfreeswan_a_OBJECTS) $(libfreeswan_a_LIBADD) - $(RANLIB) libfreeswan.a - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtoa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtot.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrtypeof.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/anyaddr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoaddr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoasr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atosubnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atoul.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copyright.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatot.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/goodmask.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initaddr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initsaid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initsubnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_build.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_debug.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_ext_bits.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pfkey_v2_parse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/portof.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rangetoa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rangetosubnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sameaddr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/satot.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnetof.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettoa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettot.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/subnettypeof.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoaddr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttodata.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoprotoport.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttosa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttosubnet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ttoul.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ultoa.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ultot.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-man3: $(dist_man3_MANS) - @$(NORMAL_INSTALL) - test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)" - @list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \ - { for i in $$list; do echo "$$i"; done; \ - } | while read p; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; echo "$$p"; \ - done | \ - sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ - sed 'N;N;s,\n, ,g' | { \ - list=; while read file base inst; do \ - if test "$$base" = "$$inst"; then list="$$list $$file"; else \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ - fi; \ - done; \ - for i in $$list; do echo "$$i"; done | $(am__base_list) | \ - while read files; do \ - test -z "$$files" || { \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ - done; } - -uninstall-man3: - @$(NORMAL_UNINSTALL) - @list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \ - files=`{ for i in $$list; do echo "$$i"; done; \ - } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ - test -z "$$files" || { \ - echo " ( cd '$(DESTDIR)$(man3dir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(man3dir)" && rm -f $$files; } - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @list='$(MANS)'; if test -n "$$list"; then \ - list=`for p in $$list; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ - if test -n "$$list" && \ - grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ - echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ - grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ - echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ - echo " typically \`make maintainer-clean' will remove them" >&2; \ - exit 1; \ - else :; fi; \ - else :; fi - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LIBRARIES) $(MANS) -installdirs: - for dir in "$(DESTDIR)$(man3dir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-man - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: install-man3 - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-man - -uninstall-man: uninstall-man3 - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-noinstLIBRARIES ctags distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-man3 install-pdf install-pdf-am install-ps \ - install-ps-am install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-man uninstall-man3 - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/libfreeswan/addrtoa.c b/src/libfreeswan/addrtoa.c deleted file mode 100644 index e1c71da3c..000000000 --- a/src/libfreeswan/addrtoa.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * addresses to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -#define NBYTES 4 /* bytes in an address */ -#define PERBYTE 4 /* three digits plus a dot or NUL */ -#define BUFLEN (NBYTES*PERBYTE) - -#if BUFLEN != ADDRTOA_BUF -#error "ADDRTOA_BUF in freeswan.h inconsistent with addrtoa() code" -#endif - -/* - - addrtoa - convert binary address to ASCII dotted decimal - */ -size_t /* space needed for full conversion */ -addrtoa(addr, format, dst, dstlen) -struct in_addr addr; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - unsigned long a = ntohl(addr.s_addr); - int i; - size_t n; - unsigned long byte; - char buf[BUFLEN]; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - p = buf; - for (i = NBYTES-1; i >= 0; i--) { - byte = (a >> (i*8)) & 0xff; - p += ultoa(byte, 10, p, PERBYTE); - if (i != 0) - *(p-1) = '.'; - } - n = p - buf; - - if (dstlen > 0) { - if (n > dstlen) - buf[dstlen - 1] = '\0'; - strcpy(dst, buf); - } - return n; -} diff --git a/src/libfreeswan/addrtot.c b/src/libfreeswan/addrtot.c deleted file mode 100644 index d1a338730..000000000 --- a/src/libfreeswan/addrtot.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * addresses to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -#define IP4BYTES 4 /* bytes in an IPv4 address */ -#define PERBYTE 4 /* three digits plus a dot or NUL */ -#define IP6BYTES 16 /* bytes in an IPv6 address */ - -/* forwards */ -static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp); -static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish); -static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp); -static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp); - -/* - - addrtot - convert binary address to text (dotted decimal or IPv6 string) - */ -size_t /* space needed for full conversion */ -addrtot(src, format, dst, dstlen) -const ip_address *src; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - const unsigned char *b; - size_t n; - char buf[1+ADDRTOT_BUF+1]; /* :address: */ - char *p; - int t = addrtypeof(src); -# define TF(t, f) (((t)<<8) | (f)) - - n = addrbytesptr(src, &b); - if (n == 0) - return 0; - - switch (TF(t, format)) { - case TF(AF_INET, 0): - n = normal4(b, n, buf, &p); - break; - case TF(AF_INET6, 0): - n = normal6(b, n, buf, &p, 1); - break; - case TF(AF_INET, 'Q'): - n = normal4(b, n, buf, &p); - break; - case TF(AF_INET6, 'Q'): - n = normal6(b, n, buf, &p, 0); - break; - case TF(AF_INET, 'r'): - n = reverse4(b, n, buf, &p); - break; - case TF(AF_INET6, 'r'): - n = reverse6(b, n, buf, &p); - break; - default: /* including (AF_INET, 'R') */ - return 0; - break; - } - - if (dstlen > 0) { - if (dstlen < n) - p[dstlen - 1] = '\0'; - strcpy(dst, p); - } - return n; -} - -/* - - normal4 - normal IPv4 address-text conversion - */ -static size_t /* size of text, including NUL */ -normal4(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - char *p; - - if (srclen != IP4BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = 0; i < IP4BYTES; i++) { - p += ultot(srcp[i], 10, p, PERBYTE); - if (i != IP4BYTES - 1) - *(p-1) = '.'; /* overwrites the NUL */ - } - *dstp = buf; - return p - buf; -} - -/* - - normal6 - normal IPv6 address-text conversion - */ -static size_t /* size of text, including NUL */ -normal6(srcp, srclen, buf, dstp, squish) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough, plus 2 */ -char **dstp; /* where to put result pointer */ -int squish; /* whether to squish out 0:0 */ -{ - int i; - unsigned long piece; - char *p; - char *q; - - if (srclen != IP6BYTES) /* "can't happen" */ - return 0; - p = buf; - *p++ = ':'; - for (i = 0; i < IP6BYTES/2; i++) { - piece = (srcp[2*i] << 8) + srcp[2*i + 1]; - p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */ - *(p-1) = ':'; /* overwrites the NUL */ - } - *p = '\0'; - q = strstr(buf, ":0:0:"); - if (squish && q != NULL) { /* zero squishing is possible */ - p = q + 1; - while (*p == '0' && *(p+1) == ':') - p += 2; - q++; - *q++ = ':'; /* overwrite first 0 */ - while (*p != '\0') - *q++ = *p++; - *q = '\0'; - if (!(*(q-1) == ':' && *(q-2) == ':')) - *--q = '\0'; /* strip final : unless :: */ - p = buf; - if (!(*p == ':' && *(p+1) == ':')) - p++; /* skip initial : unless :: */ - } else { - q = p; - *--q = '\0'; /* strip final : */ - p = buf + 1; /* skip initial : */ - } - *dstp = p; - return q - p + 1; -} - -/* - - reverse4 - IPv4 reverse-lookup conversion - */ -static size_t /* size of text, including NUL */ -reverse4(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - char *p; - - if (srclen != IP4BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = IP4BYTES-1; i >= 0; i--) { - p += ultot(srcp[i], 10, p, PERBYTE); - *(p-1) = '.'; /* overwrites the NUL */ - } - strcpy(p, "IN-ADDR.ARPA."); - *dstp = buf; - return strlen(buf) + 1; -} - -/* - - reverse6 - IPv6 reverse-lookup conversion (RFC 1886) - * A trifle inefficient, really shouldn't use ultot... - */ -static size_t /* size of text, including NUL */ -reverse6(srcp, srclen, buf, dstp) -const unsigned char *srcp; -size_t srclen; -char *buf; /* guaranteed large enough */ -char **dstp; /* where to put result pointer */ -{ - int i; - unsigned long piece; - char *p; - - if (srclen != IP6BYTES) /* "can't happen" */ - return 0; - p = buf; - for (i = IP6BYTES-1; i >= 0; i--) { - piece = srcp[i]; - p += ultot(piece&0xf, 16, p, 2); - *(p-1) = '.'; - p += ultot(piece>>4, 16, p, 2); - *(p-1) = '.'; - } - strcpy(p, "IP6.ARPA."); - *dstp = buf; - return strlen(buf) + 1; -} - -/* - - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874) - * this version removed as it was obsoleted in the end. - */ - -#ifdef ADDRTOT_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n", - argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - exit(0); -} - -struct rtab { - char *input; - char format; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0", 0, "1.2.3.0"}, - {"1:2::3:4", 0, "1:2::3:4"}, - {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"}, - {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"}, - {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."}, - /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */ - {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."}, - {NULL, 0, NULL} -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - ip_address a; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - - /* convert it *to* internal format */ - oops = ttoaddr(in, strlen(in), 0, &a); - - /* now convert it back */ - - n = addrtot(&a, r->format, buf, sizeof(buf)); - - if (n == 0 && r->output == NULL) - {} /* okay, error expected */ - - else if (n == 0) { - printf("`%s' atoasr failed\n", r->input); - status = 1; - - } else if (r->output == NULL) { - printf("`%s' atoasr succeeded unexpectedly '%c'\n", - r->input, r->format); - status = 1; - } else { - if (strcasecmp(r->output, buf) != 0) { - printf("`%s' '%c' gave `%s', expected `%s'\n", - r->input, r->format, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ADDRTOT_MAIN */ diff --git a/src/libfreeswan/addrtypeof.c b/src/libfreeswan/addrtypeof.c deleted file mode 100644 index ee3cc998f..000000000 --- a/src/libfreeswan/addrtypeof.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * extract parts of an ip_address - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - addrtypeof - get the type of an ip_address - */ -int -addrtypeof(src) -const ip_address *src; -{ - return src->u.v4.sin_family; -} - -/* - - addrbytesptr - get pointer to the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrbytesptr(src, dstp) -const ip_address *src; -const unsigned char **dstp; /* NULL means just a size query */ -{ - const unsigned char *p; - size_t n; - - switch (src->u.v4.sin_family) { - case AF_INET: - p = (const unsigned char *)&src->u.v4.sin_addr.s_addr; - n = 4; - break; - case AF_INET6: - p = (const unsigned char *)&src->u.v6.sin6_addr; - n = 16; - break; - default: - return 0; - break; - } - - if (dstp != NULL) - *dstp = p; - return n; -} - -/* - - addrlenof - get length of the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrlenof(src) -const ip_address *src; -{ - return addrbytesptr(src, NULL); -} - -/* - - addrbytesof - get the address bytes of an ip_address - */ -size_t /* 0 for error */ -addrbytesof(src, dst, dstlen) -const ip_address *src; -unsigned char *dst; -size_t dstlen; -{ - const unsigned char *p; - size_t n; - size_t ncopy; - - n = addrbytesptr(src, &p); - if (n == 0) - return 0; - - if (dstlen > 0) { - ncopy = n; - if (ncopy > dstlen) - ncopy = dstlen; - memcpy(dst, p, ncopy); - } - return n; -} diff --git a/src/libfreeswan/anyaddr.3 b/src/libfreeswan/anyaddr.3 deleted file mode 100644 index 58789cf6c..000000000 --- a/src/libfreeswan/anyaddr.3 +++ /dev/null @@ -1,86 +0,0 @@ -.TH IPSEC_ANYADDR 3 "8 Sept 2000" -.SH NAME -ipsec anyaddr \- get "any" address -.br -ipsec isanyaddr \- test address for equality to "any" address -.br -ipsec unspecaddr \- get "unspecified" address -.br -ipsec isunspecaddr \- test address for equality to "unspecified" address -.br -ipsec loopbackaddr \- get loopback address -.br -ipsec isloopbackaddr \- test address for equality to loopback address -.SH SYNOPSIS -.B "#include -.sp -.B "const char *anyaddr(int af, ip_address *dst);" -.br -.B "int isanyaddr(const ip_address *src);" -.br -.B "const char *unspecaddr(int af, ip_address *dst);" -.br -.B "int isunspecaddr(const ip_address *src);" -.br -.B "const char *loopbackaddr(int af, ip_address *dst);" -.br -.B "int isloopbackaddr(const ip_address *src);" -.SH DESCRIPTION -These functions fill in, and test for, special values of the -.I ip_address -type. -.PP -.I Anyaddr -fills in the destination -.I *dst -with the ``any'' address of address family -.IR af -(normally -.B AF_INET -or -.BR AF_INET6 ). -The IPv4 ``any'' address is the one embodied in the old -.B INADDR_ANY -macro. -.PP -.I Isanyaddr -returns -.B 1 -if the -.I src -address equals the ``any'' address, -and -.B 0 -otherwise. -.PP -Similarly, -.I unspecaddr -supplies, and -.I isunspecaddr -tests for, -the ``unspecified'' address, -which may be the same as the ``any'' address. -.PP -Similarly, -.I loopbackaddr -supplies, and -.I islookbackaddr -tests for, -the loopback address. -.PP -.IR Anyaddr , -.IR unspecaddr , -and -.I loopbackaddr -return -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.SH SEE ALSO -inet(3), ipsec_addrtot(3), ipsec_sameaddr(3) -.SH DIAGNOSTICS -Fatal errors in the address-supplying functions are: -unknown address family. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/anyaddr.c b/src/libfreeswan/anyaddr.c deleted file mode 100644 index 5b7691b7b..000000000 --- a/src/libfreeswan/anyaddr.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * special addresses - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* OpenSolaris defines strange versions of these macros */ -#ifdef __sun -#undef IN6ADDR_ANY_INIT -#define IN6ADDR_ANY_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}} - -#undef IN6ADDR_LOOPBACK_INIT -#define IN6ADDR_LOOPBACK_INIT {{{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}} -#endif - -static struct in6_addr v6any = IN6ADDR_ANY_INIT; -static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT; - -/* - - anyaddr - initialize to the any-address value - */ -err_t /* NULL for success, else string literal */ -anyaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - uint32_t v4any = htonl(INADDR_ANY); - - switch (af) { - case AF_INET: - return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst); - break; - case AF_INET6: - return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst); - break; - default: - return "unknown address family in anyaddr/unspecaddr"; - break; - } -} - -/* - - unspecaddr - initialize to the unspecified-address value - */ -err_t /* NULL for success, else string literal */ -unspecaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - return anyaddr(af, dst); -} - -/* - - loopbackaddr - initialize to the loopback-address value - */ -err_t /* NULL for success, else string literal */ -loopbackaddr(af, dst) -int af; /* address family */ -ip_address *dst; -{ - uint32_t v4loop = htonl(INADDR_LOOPBACK); - - switch (af) { - case AF_INET: - return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst); - break; - case AF_INET6: - return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst); - break; - default: - return "unknown address family in loopbackaddr"; - break; - } -} - -/* - - isanyaddr - test for the any-address value - */ -int -isanyaddr(src) -const ip_address *src; -{ - uint32_t v4any = htonl(INADDR_ANY); - int cmp; - - switch (src->u.v4.sin_family) { - case AF_INET: - cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any)); - break; - case AF_INET6: - cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any)); - break; - default: - return 0; - break; - } - - return (cmp == 0) ? 1 : 0; -} - -/* - - isunspecaddr - test for the unspecified-address value - */ -int -isunspecaddr(src) -const ip_address *src; -{ - return isanyaddr(src); -} - -/* - - isloopbackaddr - test for the loopback-address value - */ -int -isloopbackaddr(src) -const ip_address *src; -{ - uint32_t v4loop = htonl(INADDR_LOOPBACK); - int cmp; - - switch (src->u.v4.sin_family) { - case AF_INET: - cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop)); - break; - case AF_INET6: - cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop)); - break; - default: - return 0; - break; - } - - return (cmp == 0) ? 1 : 0; -} diff --git a/src/libfreeswan/atoaddr.3 b/src/libfreeswan/atoaddr.3 deleted file mode 100644 index 10da2691c..000000000 --- a/src/libfreeswan/atoaddr.3 +++ /dev/null @@ -1,291 +0,0 @@ -.TH IPSEC_ATOADDR 3 "11 June 2001" -.SH NAME -ipsec atoaddr, addrtoa \- convert Internet addresses to and from ASCII -.br -ipsec atosubnet, subnettoa \- convert subnet/mask ASCII form to and from addresses -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoaddr(const char *src, size_t srclen," -.ti +1c -.B "struct in_addr *addr);" -.br -.B "size_t addrtoa(struct in_addr addr, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.sp -.B "const char *atosubnet(const char *src, size_t srclen," -.ti +1c -.B "struct in_addr *addr, struct in_addr *mask);" -.br -.B "size_t subnettoa(struct in_addr addr, struct in_addr mask," -.ti +1c -.B "int format, char *dst, size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_ttoaddr (3) -for their replacements. -.PP -.I Atoaddr -converts an ASCII name or dotted-decimal address into a binary address -(in network byte order). -.I Addrtoa -does the reverse conversion, back to an ASCII dotted-decimal address. -.I Atosubnet -and -.I subnettoa -do likewise for the ``address/mask'' ASCII form used to write a -specification of a subnet. -.PP -An address is specified in ASCII as a -dotted-decimal address (e.g. -.BR 1.2.3.4 ), -an eight-digit network-order hexadecimal number with the usual C prefix (e.g. -.BR 0x01020304 , -which is synonymous with -.BR 1.2.3.4 ), -an eight-digit host-order hexadecimal number with a -.B 0h -prefix (e.g. -.BR 0h01020304 , -which is synonymous with -.B 1.2.3.4 -on a big-endian host and -.B 4.3.2.1 -on a little-endian host), -a DNS name to be looked up via -.IR getaddrinfo (3), -or an old-style network name to be looked up via -.IR getnetbyname (3). -.PP -A dotted-decimal address may be incomplete, in which case -ASCII-to-binary conversion implicitly appends -as many instances of -.B .0 -as necessary to bring it up to four components. -The components of a dotted-decimal address are always taken as -decimal, and leading zeros are ignored. -For example, -.B 10 -is synonymous with -.BR 10.0.0.0 , -and -.B 128.009.000.032 -is synonymous with -.BR 128.9.0.32 -(the latter example is verbatim from RFC 1166). -The result of -.I addrtoa -is always complete and does not contain leading zeros. -.PP -The letters in -a hexadecimal address may be uppercase or lowercase or any mixture thereof. -Use of hexadecimal addresses is -.B strongly -.BR discouraged ; -they are included only to save hassles when dealing with -the handful of perverted programs which already print -network addresses in hexadecimal. -.PP -DNS names may be complete (optionally terminated with a ``.'') -or incomplete, and are looked up as specified by local system configuration -(see -.IR resolver (5)). -The first value returned by -.IR getaddrinfo (3) -is used, -so with current DNS implementations, -the result when the name corresponds to more than one address is -difficult to predict. -Name lookup resorts to -.IR getnetbyname (3) -only if -.IR getaddrinfo (3) -fails. -.PP -A subnet specification is of the form \fInetwork\fB/\fImask\fR. -The -.I network -and -.I mask -can be any form acceptable to -.IR atoaddr . -In addition, the -.I mask -can be a decimal integer (leading zeros ignored) giving a bit count, -in which case -it stands for a mask with that number of high bits on and all others off -(e.g., -.B 24 -means -.BR 255.255.255.0 ). -In any case, the mask must be contiguous -(a sequence of high bits on and all remaining low bits off). -As a special case, the subnet specification -.B %default -is a synonym for -.BR 0.0.0.0/0 . -.PP -.I Atosubnet -ANDs the mask with the address before returning, -so that any non-network bits in the address are turned off -(e.g., -.B 10.1.2.3/24 -is synonymous with -.BR 10.1.2.0/24 ). -.I Subnettoa -generates the decimal-integer-bit-count -form of the mask, -with no leading zeros, -unless the mask is non-contiguous. -.PP -The -.I srclen -parameter of -.I atoaddr -and -.I atosubnet -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I dstlen -parameter of -.I addrtoa -and -.I subnettoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines constants, -.B ADDRTOA_BUF -and -.BR SUBNETTOA_BUF , -which are the sizes of buffers just large enough for worst-case results. -.PP -The -.I format -parameter of -.I addrtoa -and -.I subnettoa -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available. -This parameter is a hedge against future needs. -.PP -The ASCII-to-binary functions return NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -The binary-to-ASCII functions return -.B 0 -for a failure, and otherwise -always return the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoaddr -are: -empty input; -attempt to allocate temporary storage for a very long name failed; -name lookup failed; -syntax error in dotted-decimal form; -dotted-decimal component too large to fit in 8 bits. -.PP -Fatal errors in -.I atosubnet -are: -no -.B / -in -.IR src ; -.I atoaddr -error in conversion of -.I network -or -.IR mask ; -bit-count mask too big; -mask non-contiguous. -.PP -Fatal errors in -.I addrtoa -and -.I subnettoa -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The interpretation of incomplete dotted-decimal addresses -(e.g. -.B 10/24 -means -.BR 10.0.0.0/24 ) -differs from that of some older conversion -functions, e.g. those of -.IR inet (3). -The behavior of the older functions has never been -particularly consistent or particularly useful. -.PP -Ignoring leading zeros in dotted-decimal components and bit counts -is arguably the most useful behavior in this application, -but it might occasionally cause confusion with the historical use of leading -zeros to denote octal numbers. -.PP -It is barely possible that somebody, somewhere, -might have a legitimate use for non-contiguous subnet masks. -.PP -.IR Getnetbyname (3) -is a historical dreg. -.PP -The restriction of ASCII-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The ASCII-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoaddr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoaddr.c b/src/libfreeswan/atoaddr.c deleted file mode 100644 index a3643801e..000000000 --- a/src/libfreeswan/atoaddr.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * conversion from ASCII forms of addresses to internal ones - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There - * is deliberately no way to interpret it as 26 (i.e., as octal). - */ - -/* - * Legal characters in a domain name. Underscore technically is not, - * but is a common misunderstanding. - */ -static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; - -static const char *try8hex(const char *, size_t, struct in_addr *); -static const char *try8hosthex(const char *, size_t, struct in_addr *); -static const char *trydotted(const char *, size_t, struct in_addr *); -static const char *getbyte(const char **, const char *, int *); - -/* - - atoaddr - convert ASCII name or dotted-decimal address to binary address - */ -const char * /* NULL for success, else string literal */ -atoaddr(src, srclen, addrp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -struct in_addr *addrp; -{ - struct addrinfo hints, *res; - struct netent *ne = NULL; - const char *oops, *msg = NULL; -# define HEXLEN 10 /* strlen("0x11223344") */ -# ifndef ATOADDRBUF -# define ATOADDRBUF 100 -# endif - char namebuf[ATOADDRBUF]; - char *p = namebuf; - char *q; - int error; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - /* might it be hex? */ - if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x')) - return try8hex(src+2, srclen-2, addrp); - if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h')) - return try8hosthex(src+2, srclen-2, addrp); - - /* try it as dotted decimal */ - oops = trydotted(src, srclen, addrp); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* it *was* probably meant as a d.q. */ - - /* try it as a name -- first, NUL-terminate it */ - if (srclen > sizeof(namebuf)-1) { - p = (char *) MALLOC(srclen+1); - if (p == NULL) - return "unable to allocate temporary space for name"; - } - p[0] = '\0'; - strncat(p, src, srclen); - - /* next, check that it's a vaguely legal name */ - for (q = p; *q != '\0'; q++) - { - if (!isprint(*q)) - { - msg = "unprintable character in name"; - goto error; - } - } - if (strspn(p, namechars) != srclen) - { - msg = "illegal (non-DNS-name) character in name"; - goto error; - } - - /* try as host name, failing that as /etc/networks network name */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - error = getaddrinfo(p, NULL, &hints, &res); - if (error != 0) - { - ne = getnetbyname(p); - if (ne == NULL) - { - msg = "name lookup failed"; - goto error; - } - addrp->s_addr = htonl(ne->n_net); - } - else - { - struct sockaddr_in *in = (struct sockaddr_in*)res->ai_addr; - memcpy(&addrp->s_addr, &in->sin_addr.s_addr, sizeof(addrp->s_addr)); - freeaddrinfo(res); - } - -error: - if (p != namebuf) - { - FREE(p); - } - - return msg; -} - -/* - - try8hosthex - try conversion as an eight-digit host-order hex number - */ -const char * /* NULL for success, else string literal */ -try8hosthex(src, srclen, addrp) -const char *src; -size_t srclen; /* should be 8 */ -struct in_addr *addrp; -{ - const char *oops; - unsigned long addr; - - if (srclen != 8) - return "internal error, try8hex called with bad length"; - - oops = atoul(src, srclen, 16, &addr); - if (oops != NULL) - return oops; - - addrp->s_addr = addr; - return NULL; -} - -/* - - try8hex - try conversion as an eight-digit network-order hex number - */ -const char * /* NULL for success, else string literal */ -try8hex(src, srclen, addrp) -const char *src; -size_t srclen; /* should be 8 */ -struct in_addr *addrp; -{ - const char *oops; - - oops = try8hosthex(src, srclen, addrp); - if (oops != NULL) - return oops; - - addrp->s_addr = htonl(addrp->s_addr); - return NULL; -} - -/* - - trydotted - try conversion as dotted decimal - * - * If the first char of a complaint is '?', that means "didn't look like - * dotted decimal at all". - */ -const char * /* NULL for success, else string literal */ -trydotted(src, srclen, addrp) -const char *src; -size_t srclen; -struct in_addr *addrp; -{ - const char *stop = src + srclen; /* just past end */ - int byte; - const char *oops; - unsigned long addr; - int i; -# define NBYTES 4 -# define BYTE 8 - - addr = 0; - for (i = 0; i < NBYTES && src < stop; i++) { - oops = getbyte(&src, stop, &byte); - if (oops != NULL) { - if (*oops != '?') - return oops; /* bad number */ - if (i > 1) - return oops+1; /* failed number */ - return oops; /* with leading '?' */ - } - addr = (addr << BYTE) | byte; - if (i < 3 && src < stop && *src++ != '.') { - if (i == 0) - return "?syntax error in dotted-decimal address"; - else - return "syntax error in dotted-decimal address"; - } - } - addr <<= (NBYTES - i) * BYTE; - if (src != stop) - return "extra garbage on end of dotted-decimal address"; - - addrp->s_addr = htonl(addr); - return NULL; -} - -/* - - getbyte - try to scan a byte in dotted decimal - * A subtlety here is that all this arithmetic on ASCII digits really is - * highly portable -- ANSI C guarantees that digits 0-9 are contiguous. - * It's easier to just do it ourselves than set up for a call to atoul(). - * - * If the first char of a complaint is '?', that means "didn't look like a - * number at all". - */ -const char * /* NULL for success, else string literal */ -getbyte(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -int *retp; /* return-value pointer */ -{ - char c; - const char *p; - int no; - - if (*srcp >= stop) - return "?empty number in dotted-decimal address"; - - if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x')) - return "hex numbers not supported in dotted-decimal addresses"; -#ifdef NOLEADINGZEROS - if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1))) - return "octal numbers not supported in dotted-decimal addresses"; -#endif /* NOLEADINGZEROS */ - - /* must be decimal, if it's numeric at all */ - no = 0; - p = *srcp; - while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') { - no = no*10 + (c - '0'); - p++; - } - if (p == *srcp) - return "?non-numeric component in dotted-decimal address"; - *srcp = p; - if (no > 255) - return "byte overflow in dotted-decimal address"; - *retp = no; - return NULL; -} diff --git a/src/libfreeswan/atoasr.3 b/src/libfreeswan/atoasr.3 deleted file mode 100644 index 0b9a5fea3..000000000 --- a/src/libfreeswan/atoasr.3 +++ /dev/null @@ -1,185 +0,0 @@ -.TH IPSEC_ATOASR 3 "11 June 2001" -.SH NAME -ipsec atoasr \- convert ASCII to Internet address, subnet, or range -.br -ipsec rangetoa \- convert Internet address range to ASCII -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoasr(const char *src, size_t srclen," -.ti +1c -.B "char *type, struct in_addr *addrs);" -.br -.B "size_t rangetoa(struct in_addr *addrs, int format, -.ti +1c -.B "char *dst, size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; -there is no current equivalent, -because so far they have not proved useful. -.PP -.I Atoasr -converts an ASCII address, subnet, or address range -into a suitable combination of binary addresses -(in network byte order). -.I Rangetoa -converts an address range back into ASCII, -using dotted-decimal form for the addresses -(the other reverse conversions are handled by -.IR ipsec_addrtoa (3) -and -.IR ipsec_subnettoa (3)). -.PP -A single address can be any form acceptable to -.IR ipsec_atoaddr (3): -dotted decimal, DNS name, or hexadecimal number. -A subnet -specification uses the form \fInetwork\fB/\fImask\fR -interpreted by -.IR ipsec_atosubnet (3). -.PP -An address range is two -.IR ipsec_atoaddr (3) -addresses separated by a -.B ... -delimiter. -If there are four dots rather than three, the first is taken as -part of the begin address, -e.g. for a complete DNS name which ends with -.B . -to suppress completion attempts. -The begin address of a range must be -less than or equal to the end address. -.PP -The -.I srclen -parameter of -.I atoasr -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I type -parameter of -.I atoasr -must point to a -.B char -variable used to record which form was found. -The -.I addrs -parameter must point to a two-element array of -.B "struct in_addr" -which receives the results. -The values stored into -.BR *type , -and the corresponding values in the array, are: -.PP -.ta 3c +2c +3c - *type addrs[0] addrs[1] -.sp 0.8 -address \&\fB'a'\fR address - -.br -subnet \&\fB's'\fR network mask -.br -range \&\fB'r'\fR begin end -.PP -The -.I dstlen -parameter of -.I rangetoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines a constant, -.BR RANGETOA_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I rangetoa -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available. -This parameter is a hedge against future needs. -.PP -.I Atoasr -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Rangetoa -returns -.B 0 -for a failure, and otherwise -always returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -ipsec_atoaddr(3), ipsec_atosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoasr -are: -empty input; -error in -.IR ipsec_atoaddr (3) -or -.IR ipsec_atosubnet (3) -during conversion; -begin address of range exceeds end address. -.PP -Fatal errors in -.I rangetoa -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoasr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoasr.c b/src/libfreeswan/atoasr.c deleted file mode 100644 index ad62ef46b..000000000 --- a/src/libfreeswan/atoasr.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * convert from ASCII form of address/subnet/range to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - atoasr - convert ASCII to address, subnet, or range - */ -const char * /* NULL for success, else string literal */ -atoasr(src, srclen, typep, addrsp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -char *typep; /* return type code: 'a', 's', 'r' */ -struct in_addr addrsp[2]; -{ - const char *punct; - const char *stop; - const char *oops; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - /* subnet is easy to spot */ - punct = memchr(src, '/', srclen); - if (punct != NULL) { - *typep = 's'; - return atosubnet(src, srclen, &addrsp[0], &addrsp[1]); - } - - /* try for a range */ - stop = src + srclen; - for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL; - punct++) - if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.') - break; /* NOTE BREAK OUT */ - if (punct == NULL) { - /* didn't find the range delimiter, must be plain address */ - *typep = 'a'; - return atoaddr(src, srclen, &addrsp[0]); - } - - /* looks like a range */ - *typep = 'r'; - if (stop - punct > 4 && *(punct+3) == '.') - punct++; /* first dot is trailing dot of name */ - oops = atoaddr(src, punct - src, &addrsp[0]); - if (oops != NULL) - return oops; - oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]); - if (oops != NULL) - return oops; - if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr)) - return "invalid range, begin > end"; - return NULL; -} - - - -#ifdef ATOASR_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - struct in_addr a[2]; - char buf[100]; - const char *oops; - size_t n; - char type; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n", - argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = atoasr(argv[1], 0, &type, a); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - switch (type) { - case 'a': - n = addrtoa(a[0], 0, buf, sizeof(buf)); - break; - case 's': - n = subnettoa(a[0], a[1], 0, buf, sizeof(buf)); - break; - case 'r': - n = rangetoa(a, 0, buf, sizeof(buf)); - break; - default: - fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type); - exit(1); - break; - } - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - fprintf(stderr, "%s ", inet_ntoa(a[0])); - fprintf(stderr, "%s", inet_ntoa(a[1])); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0", "1.2.3.0"}, - {"1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {"1.2.3.0...1.2.3.5", "1.2.3.0...1.2.3.5"}, - {"1.2.3.4.5", NULL}, - {"1.2.3.4/", NULL}, - {"1.2.3.4...", NULL}, - {"1.2.3.4....", NULL}, - {"localhost/32", "127.0.0.1/32"}, - {"localhost...127.0.0.3", "127.0.0.1...127.0.0.3"}, - {"127.0.0.0...localhost", "127.0.0.0...127.0.0.1"}, - {"127.0.0.3...localhost", NULL}, - {NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - struct in_addr a[2]; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - char type; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = atoasr(in, 0, &type, a); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' atoasr failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' atoasr succeeded unexpectedly '%c'\n", - r->input, type); - status = 1; - } else { - switch (type) { - case 'a': - n = addrtoa(a[0], 0, buf, sizeof(buf)); - break; - case 's': - n = subnettoa(a[0], a[1], 0, buf, sizeof(buf)); - break; - case 'r': - n = rangetoa(a, 0, buf, sizeof(buf)); - break; - default: - fprintf(stderr, "`%s' unknown type '%c'\n", - r->input, type); - n = 0; - status = 1; - break; - } - if (n > sizeof(buf)) { - printf("`%s' '%c' reverse failed: need %ld\n", - r->input, type, (long)n); - status = 1; - } else if (n > 0 && strcmp(r->output, buf) != 0) { - printf("`%s' '%c' gave `%s', expected `%s'\n", - r->input, type, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ATOASR_MAIN */ diff --git a/src/libfreeswan/atosubnet.c b/src/libfreeswan/atosubnet.c deleted file mode 100644 index 8b2bfa17e..000000000 --- a/src/libfreeswan/atosubnet.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * convert from ASCII form of subnet specification to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -#ifndef DEFAULTSUBNET -#define DEFAULTSUBNET "%default" -#endif - -/* - - atosubnet - convert ASCII "addr/mask" to address and mask - * Mask can be integer bit count. - */ -const char * /* NULL for success, else string literal */ -atosubnet(src, srclen, addrp, maskp) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -struct in_addr *addrp; -struct in_addr *maskp; -{ - const char *slash; - const char *mask; - size_t mlen; - const char *oops; - unsigned long bc; - static char def[] = DEFAULTSUBNET; -# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */ - static char defis[] = "0/0"; -# define DEFILEN (sizeof(defis) - 1) - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) { - src = defis; - srclen = DEFILEN; - } - - slash = memchr(src, '/', srclen); - if (slash == NULL) - return "no / in subnet specification"; - mask = slash + 1; - mlen = srclen - (mask - src); - - oops = atoaddr(src, slash-src, addrp); - if (oops != NULL) - return oops; - - oops = atoul(mask, mlen, 10, &bc); - if (oops == NULL) { - /* atoul succeeded, it's a bit-count mask */ - if (bc > ABITS) - return "bit-count mask too large"; -#ifdef NOLEADINGZEROS - if (mlen > 1 && *mask == '0') - return "octal not allowed in mask"; -#endif /* NOLEADINGZEROS */ - *maskp = bitstomask((int)bc); - } else { - oops = atoaddr(mask, mlen, maskp); - if (oops != NULL) - return oops; - if (!goodmask(*maskp)) - return "non-contiguous mask"; - } - - addrp->s_addr &= maskp->s_addr; - return NULL; -} - - - -#ifdef ATOSUBNET_MAIN - -#include -#include -#include -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - struct in_addr a; - struct in_addr m; - char buf[100]; - const char *oops; - size_t n; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = atosubnet(argv[1], 0, &a, &m); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettoa(a, m, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - fprintf(stderr, "%s/", inet_ntoa(a)); - fprintf(stderr, "%s", inet_ntoa(m)); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {"1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {"1.2.3.0/24", "1.2.3.0/24"}, - {"1.2.3.1/255.255.255.240", "1.2.3.0/28"}, - {"1.2.3.1/32", "1.2.3.1/32"}, - {"1.2.3.1/0", "0.0.0.0/0"}, -/* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */ - {"1.2.3.1/255.255.127.0", NULL}, - {"128.009.000.032/32", "128.9.0.32/32"}, - {"128.0x9.0.32/32", NULL}, - {"0x80090020/32", "128.9.0.32/32"}, - {"0x800x0020/32", NULL}, - {"128.9.0.32/0xffFF0000", "128.9.0.0/16"}, - {"128.9.0.32/0xff0000FF", NULL}, - {"128.9.0.32/0x0000ffFF", NULL}, - {"128.9.0.32/0x00ffFF0000", NULL}, - {"128.9.0.32/0xffFF", NULL}, - {"128.9.0.32.27/32", NULL}, - {"128.9.0k32/32", NULL}, - {"328.9.0.32/32", NULL}, - {"128.9..32/32", NULL}, - {"10/8", "10.0.0.0/8"}, - {"10.0/8", "10.0.0.0/8"}, - {"10.0.0/8", "10.0.0.0/8"}, - {"10.0.1/24", "10.0.1.0/24"}, - {"_", NULL}, - {"_/_", NULL}, - {"1.2.3.1", NULL}, - {"1.2.3.1/_", NULL}, - {"1.2.3.1/24._", NULL}, - {"1.2.3.1/99", NULL}, - {"localhost/32", "127.0.0.1/32"}, - {"%default", "0.0.0.0/0"}, - {NULL, NULL} -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - struct in_addr a; - struct in_addr m; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = atosubnet(in, 0, &a, &m); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' atosubnet failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' atosubnet succeeded unexpectedly\n", - r->input); - status = 1; - } else { - n = subnettoa(a, m, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' subnettoa failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* ATOSUBNET_MAIN */ diff --git a/src/libfreeswan/atoul.3 b/src/libfreeswan/atoul.3 deleted file mode 100644 index 6737b6b54..000000000 --- a/src/libfreeswan/atoul.3 +++ /dev/null @@ -1,160 +0,0 @@ -.TH IPSEC_ATOUL 3 "11 June 2001" -.SH NAME -ipsec atoul, ultoa \- convert unsigned-long numbers to and from ASCII -.SH SYNOPSIS -.B "#include -.sp -.B "const char *atoul(const char *src, size_t srclen," -.ti +1c -.B "int base, unsigned long *n);" -.br -.B "size_t ultoa(unsigned long n, int base, char *dst," -.ti +1c -.B "size_t dstlen);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_ttoul (3) -for their replacements. -.PP -.I Atoul -converts an ASCII number into a binary -.B "unsigned long" -value. -.I Ultoa -does the reverse conversion, back to an ASCII version. -.PP -Numbers are specified in ASCII as -decimal (e.g. -.BR 123 ), -octal with a leading zero (e.g. -.BR 012 , -which has value 10), -or hexadecimal with a leading -.B 0x -(e.g. -.BR 0x1f , -which has value 31) -in either upper or lower case. -.PP -The -.I srclen -parameter of -.I atoul -specifies the length of the ASCII string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I base -parameter of -.I atoul -can be -.BR 8 , -.BR 10 , -or -.BR 16 , -in which case the number supplied is assumed to be of that form -(and in the case of -.BR 16 , -to lack any -.B 0x -prefix). -It can also be -.BR 0 , -in which case the number is examined for a leading zero -or a leading -.B 0x -to determine its base, -or -.B 13 -(halfway between 10 and 16), -which has the same effect as -.B 0 -except that a non-hexadecimal -number is considered decimal regardless of any leading zero. -.PP -The -.I dstlen -parameter of -.I ultoa -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -.PP -The -.I base -parameter of -.I ultoa -must be -.BR 8 , -.BR 10 , -or -.BR 16 . -.PP -.I Atoul -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Ultoa -returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -atol(3), strtoul(3) -.SH DIAGNOSTICS -Fatal errors in -.I atoul -are: -empty input; -unknown -.IR base ; -non-digit character found; -number too large for an -.BR "unsigned long" . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -There is no provision for reporting an invalid -.I base -parameter given to -.IR ultoa . -.PP -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = atoul( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/atoul.c b/src/libfreeswan/atoul.c deleted file mode 100644 index d8e1528cb..000000000 --- a/src/libfreeswan/atoul.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * convert from ASCII form of unsigned long to binary - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - atoul - convert ASCII substring to unsigned long number - */ -const char * /* NULL for success, else string literal */ -atoul(src, srclen, base, resultp) -const char *src; -size_t srclen; /* 0 means strlen(src) */ -int base; /* 0 means figure it out */ -unsigned long *resultp; -{ - const char *stop; - static char hex[] = "0123456789abcdef"; - static char uchex[] = "0123456789ABCDEF"; - int d; - char c; - char *p; - unsigned long r; - unsigned long rlimit; - int dlimit; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (base == 0 || base == 13) { - if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x')) - return atoul(src+2, srclen-2, 16, resultp); - if (srclen > 1 && *src == '0' && base != 13) - return atoul(src+1, srclen-1, 8, resultp); - return atoul(src, srclen, 10, resultp); - } - if (base != 8 && base != 10 && base != 16) - return "unsupported number base"; - - r = 0; - stop = src + srclen; - if (base == 16) { - while (src < stop) { - c = *src++; - p = strchr(hex, c); - if (p != NULL) - d = p - hex; - else { - p = strchr(uchex, c); - if (p == NULL) - return "non-hex-digit in hex number"; - d = p - uchex; - } - r = (r << 4) | d; - } - /* defer length check to catch invalid digits first */ - if (srclen > sizeof(unsigned long) * 2) - return "hex number too long"; - } else { - rlimit = ULONG_MAX / base; - dlimit = (int)(ULONG_MAX - rlimit*base); - while (src < stop) { - c = *src++; - d = c - '0'; - if (d < 0 || d >= base) - return "non-digit in number"; - if (r > rlimit || (r == rlimit && d > dlimit)) - return "unsigned-long overflow"; - r = r*base + d; - } - } - - *resultp = r; - return NULL; -} diff --git a/src/libfreeswan/copyright.c b/src/libfreeswan/copyright.c deleted file mode 100644 index e55e849f7..000000000 --- a/src/libfreeswan/copyright.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * return IPsec copyright notice - * Copyright (C) 2001, 2002 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static const char *co[] = { - "Copyright (C) 1999-2009 Henry Spencer, Richard Guy Briggs,", - " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,", - " Michael Richardson, Angelos D. Keromytis, John Ioannidis,", - "", - " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,", - " Stephane Laroche, Kai Martius, Stephan Scholz, Tuomo Soini, Herbert Xu,", - "", - " Martin Berner, Marco Bertossa, David Buechi, Ueli Galizzi,", - " Christoph Gysin, Andreas Hess, Patric Lichtsteiner, Michael Meier,", - " Andreas Schleiss, Ariane Seiler, Mario Strasser, Lukas Suter,", - " Roger Wegmann, Simon Zwahlen,", - " ZHW Zuercher Hochschule Winterthur (Switzerland).", - "", - " Philip Boetschi, Tobias Brunner, Sansar Choinyambuu, Adrian Doerig,", - " Andreas Eigenmann, Fabian Hartmann, Noah Heusser, Jan Hutter,", - " Thomas Kallenberg, Daniel Roethlisberger, Joel Stillhart, Martin Willi,", - " Daniel Wydler, Andreas Steffen,", - " HSR Hochschule fuer Technik Rapperswil (Switzerland).", - "", - "This program is free software; you can redistribute it and/or modify it", - "under the terms of the GNU General Public License as published by the", - "Free Software Foundation; either version 2 of the License, or (at your", - "option) any later version. See .", - "", - "This program is distributed in the hope that it will be useful, but", - "WITHOUT ANY WARRANTY; without even the implied warranty of", - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General", - "Public License (file COPYING in the distribution) for more details.", - NULL -}; - -/* - - ipsec_copyright_notice - return copyright notice, as a vector of strings - */ -const char ** -ipsec_copyright_notice() -{ - return co; -} diff --git a/src/libfreeswan/datatot.c b/src/libfreeswan/datatot.c deleted file mode 100644 index e3b9d6417..000000000 --- a/src/libfreeswan/datatot.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * convert from binary data (e.g. key) to text form - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static void convert(const char *src, size_t nreal, int format, char *out); - -/* - - datatot - convert data bytes to text - */ -size_t /* true length (with NUL) for success */ -datatot(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t inblocksize; /* process this many bytes at a time */ - size_t outblocksize; /* producing this many */ - size_t breakevery; /* add a _ every this many (0 means don't) */ - size_t sincebreak; /* output bytes since last _ */ - char breakchar; /* character used to break between groups */ - char inblock[10]; /* enough for any format */ - char outblock[10]; /* enough for any format */ - char fake[1]; /* fake output area for dstlen == 0 */ - size_t needed; /* return value */ - char *stop; /* where the terminating NUL will go */ - size_t ntodo; /* remaining input */ - size_t nreal; - char *out; - char *prefix; - - breakevery = 0; - breakchar = '_'; - - switch (format) { - case 0: - case 'h': - format = 'x'; - breakevery = 8; - /* FALLTHROUGH */ - case 'x': - inblocksize = 1; - outblocksize = 2; - prefix = "0x"; - break; - case ':': - breakevery = 2; - breakchar = ':'; - /* FALLTHROUGH */ - case 16: - inblocksize = 1; - outblocksize = 2; - prefix = ""; - format = 'x'; - break; - case 's': - inblocksize = 3; - outblocksize = 4; - prefix = "0s"; - break; - case 64: /* beware, equals ' ' */ - inblocksize = 3; - outblocksize = 4; - prefix = ""; - format = 's'; - break; - default: - return 0; - break; - } - assert(inblocksize < sizeof(inblock)); - assert(outblocksize < sizeof(outblock)); - assert(breakevery % outblocksize == 0); - - if (srclen == 0) - return 0; - ntodo = srclen; - - if (dstlen == 0) { /* dispose of awkward special case */ - dst = fake; - dstlen = 1; - } - stop = dst + dstlen - 1; - - nreal = strlen(prefix); - needed = nreal; /* for starters */ - if (dstlen <= nreal) { /* prefix won't fit */ - strncpy(dst, prefix, dstlen - 1); - dst += dstlen - 1; - } else { - strcpy(dst, prefix); - dst += nreal; - } - assert(dst <= stop); - sincebreak = 0; - - while (ntodo > 0) { - if (ntodo < inblocksize) { /* incomplete input */ - memset(inblock, 0, sizeof(inblock)); - memcpy(inblock, src, ntodo); - src = inblock; - nreal = ntodo; - ntodo = inblocksize; - } else - nreal = inblocksize; - out = (outblocksize > stop - dst) ? outblock : dst; - - convert(src, nreal, format, out); - needed += outblocksize; - sincebreak += outblocksize; - if (dst < stop) { - if (out != dst) { - assert(outblocksize > stop - dst); - memcpy(dst, out, stop - dst); - dst = stop; - } else - dst += outblocksize; - } - - src += inblocksize; - ntodo -= inblocksize; - if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) { - if (dst < stop) - *dst++ = breakchar; - needed++; - sincebreak = 0; - } - } - - assert(dst <= stop); - *dst++ = '\0'; - needed++; - - return needed; -} - -/* - - convert - convert one input block to one output block - */ -static void -convert(src, nreal, format, out) -const char *src; -size_t nreal; /* how much of the input block is real */ -int format; -char *out; -{ - static char hex[] = "0123456789abcdef"; - static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - unsigned char c; - unsigned char c1, c2, c3; - - assert(nreal > 0); - switch (format) { - case 'x': - assert(nreal == 1); - c = (unsigned char)*src; - *out++ = hex[c >> 4]; - *out++ = hex[c & 0xf]; - break; - case 's': - c1 = (unsigned char)*src++; - c2 = (unsigned char)*src++; - c3 = (unsigned char)*src++; - *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */ - c = (c1 & 0x3) << 4; /* bottom 2 of c1... */ - c |= c2 >> 4; /* ...top 4 of c2 */ - *out++ = base64[c]; - if (nreal == 1) - *out++ = '='; - else { - c = (c2 & 0xf) << 2; /* bottom 4 of c2... */ - c |= c3 >> 6; /* ...top 2 of c3 */ - *out++ = base64[c]; - } - if (nreal <= 2) - *out++ = '='; - else - *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */ - break; - default: - assert(nreal == 0); /* unknown format */ - break; - } -} - -/* - - datatoa - convert data to ASCII - * backward-compatibility synonym for datatot - */ -size_t /* true length (with NUL) for success */ -datatoa(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - return datatot(src, srclen, format, dst, dstlen); -} - -/* - - bytestoa - convert data bytes to ASCII - * backward-compatibility synonym for datatot - */ -size_t /* true length (with NUL) for success */ -bytestoa(src, srclen, format, dst, dstlen) -const char *src; -size_t srclen; -int format; /* character indicating what format */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - return datatot(src, srclen, format, dst, dstlen); -} diff --git a/src/libfreeswan/freeswan.h b/src/libfreeswan/freeswan.h deleted file mode 100644 index 724165bde..000000000 --- a/src/libfreeswan/freeswan.h +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef _FREESWAN_H -/* - * header file for FreeS/WAN library functions - * Copyright (C) 1998, 1999, 2000 Henry Spencer. - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#define _FREESWAN_H /* seen it, no need to see it again */ - -# include -# include -# include - -# define DEBUG_NO_STATIC static - -#include -#include - -/* - * We assume header files have IPv6 (i.e. kernel version >= 2.1.0) - */ -#define NET_21 - -#ifndef IPPROTO_COMP -# define IPPROTO_COMP 108 -#endif /* !IPPROTO_COMP */ - -#ifndef IPPROTO_INT -# define IPPROTO_INT 61 -#endif /* !IPPROTO_INT */ - -#ifdef CONFIG_IPSEC_DEBUG -# define DEBUG_NO_STATIC -#else /* CONFIG_IPSEC_DEBUG */ -# define DEBUG_NO_STATIC static -#endif /* CONFIG_IPSEC_DEBUG */ - -#define ESPINUDP_WITH_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ -#define ESPINUDP_WITH_NON_ESP 2 /* draft-ietf-ipsec-nat-t-ike-02 */ - -/* - * Basic data types for the address-handling functions. - * ip_address and ip_subnet are supposed to be opaque types; do not - * use their definitions directly, they are subject to change! - */ - -/* then the main types */ -typedef struct { - union { - struct sockaddr_in v4; - struct sockaddr_in6 v6; - } u; -} ip_address; -typedef struct { - ip_address addr; - int maskbits; -} ip_subnet; - -/* and the SA ID stuff */ -typedef u_int32_t ipsec_spi_t; -typedef struct { /* to identify an SA, we need: */ - ip_address dst; /* A. destination host */ - ipsec_spi_t spi; /* B. 32-bit SPI, assigned by dest. host */ -# define SPI_PASS 256 /* magic values... */ -# define SPI_DROP 257 /* ...for use... */ -# define SPI_REJECT 258 /* ...with SA_INT */ -# define SPI_HOLD 259 -# define SPI_TRAP 260 -# define SPI_TRAPSUBNET 261 - int proto; /* C. protocol */ -# define SA_ESP 50 /* IPPROTO_ESP */ -# define SA_AH 51 /* IPPROTO_AH */ -# define SA_IPIP 4 /* IPPROTO_IPIP */ -# define SA_COMP 108 /* IPPROTO_COMP */ -# define SA_INT 61 /* IANA reserved for internal use */ -} ip_said; -struct sa_id { /* old v4-only version */ - struct in_addr dst; - ipsec_spi_t spi; - int proto; -}; - -/* misc */ -struct prng { /* pseudo-random-number-generator guts */ - unsigned char sbox[256]; - int i, j; - unsigned long count; -}; - - -/* - * definitions for user space, taken from freeswan/ipsec_sa.h - */ -typedef uint32_t IPsecSAref_t; - -#define IPSEC_SA_REF_TABLE_NUM_ENTRIES (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH) - -#define IPSEC_SA_REF_FIELD_WIDTH (8 * sizeof(IPsecSAref_t)) - -#define IPsecSAref2NFmark(x) ((x) << (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH)) -#define NFmark2IPsecSAref(x) ((x) >> (IPSEC_SA_REF_FIELD_WIDTH - IPSEC_SA_REF_TABLE_IDX_WIDTH)) - -#define IPSEC_SAREF_NULL (~((IPsecSAref_t)0)) - -/* GCC magic for use in function definitions! */ -#ifdef GCC_LINT -# define PRINTF_LIKE(n) __attribute__ ((format(printf, n, n+1))) -# define NEVER_RETURNS __attribute__ ((noreturn)) -# define UNUSED __attribute__ ((unused)) -# define BLANK_FORMAT " " /* GCC_LINT whines about empty formats */ -#else -# define PRINTF_LIKE(n) /* ignore */ -# define NEVER_RETURNS /* ignore */ -# define UNUSED /* ignore */ -# define BLANK_FORMAT "" -#endif - - - - - -/* - * new IPv6-compatible functions - */ - -/* text conversions */ -err_t ttoul(const char *src, size_t srclen, int format, unsigned long *dst); -size_t ultot(unsigned long src, int format, char *buf, size_t buflen); -#define ULTOT_BUF (22+1) /* holds 64 bits in octal */ -err_t ttoaddr(const char *src, size_t srclen, int af, ip_address *dst); -err_t tnatoaddr(const char *src, size_t srclen, int af, ip_address *dst); -size_t addrtot(const ip_address *src, int format, char *buf, size_t buflen); -/* RFC 1886 old IPv6 reverse-lookup format is the bulkiest */ -#define ADDRTOT_BUF (32*2 + 3 + 1 + 3 + 1 + 1) -err_t ttosubnet(const char *src, size_t srclen, int af, ip_subnet *dst); -size_t subnettot(const ip_subnet *src, int format, char *buf, size_t buflen); -#define SUBNETTOT_BUF (ADDRTOT_BUF + 1 + 3) -err_t ttosa(const char *src, size_t srclen, ip_said *dst); -size_t satot(const ip_said *src, int format, char *bufptr, size_t buflen); -#define SATOT_BUF (5 + ULTOA_BUF + 1 + ADDRTOT_BUF) -err_t ttodata(const char *src, size_t srclen, int base, char *buf, - size_t buflen, size_t *needed); -err_t ttodatav(const char *src, size_t srclen, int base, - char *buf, size_t buflen, size_t *needed, - char *errp, size_t errlen, unsigned int flags); -#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */ -#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/ -#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */ - -size_t datatot(const char *src, size_t srclen, int format, char *buf, - size_t buflen); -err_t ttoprotoport(char *src, size_t src_len, u_int8_t *proto, u_int16_t *port, - bool *has_port_wildcard); - -/* initializations */ -void initsaid(const ip_address *addr, ipsec_spi_t spi, int proto, ip_said *dst); -err_t loopbackaddr(int af, ip_address *dst); -err_t unspecaddr(int af, ip_address *dst); -err_t anyaddr(int af, ip_address *dst); -err_t initaddr(const unsigned char *src, size_t srclen, int af, ip_address *dst); -err_t initsubnet(const ip_address *addr, int maskbits, int clash, ip_subnet *dst); -err_t addrtosubnet(const ip_address *addr, ip_subnet *dst); - -/* misc. conversions and related */ -err_t rangetosubnet(const ip_address *from, const ip_address *to, ip_subnet *dst); -int addrtypeof(const ip_address *src); -int subnettypeof(const ip_subnet *src); -size_t addrlenof(const ip_address *src); -size_t addrbytesptr(const ip_address *src, const unsigned char **dst); -size_t addrbytesof(const ip_address *src, unsigned char *dst, size_t dstlen); -int masktocount(const ip_address *src); -void networkof(const ip_subnet *src, ip_address *dst); -void maskof(const ip_subnet *src, ip_address *dst); - -/* tests */ -int sameaddr(const ip_address *a, const ip_address *b); -int addrcmp(const ip_address *a, const ip_address *b); -int samesubnet(const ip_subnet *a, const ip_subnet *b); -int addrinsubnet(const ip_address *a, const ip_subnet *s); -int subnetinsubnet(const ip_subnet *a, const ip_subnet *b); -int subnetishost(const ip_subnet *s); -int samesaid(const ip_said *a, const ip_said *b); -int sameaddrtype(const ip_address *a, const ip_address *b); -int samesubnettype(const ip_subnet *a, const ip_subnet *b); -int isanyaddr(const ip_address *src); -int isunspecaddr(const ip_address *src); -int isloopbackaddr(const ip_address *src); - -/* low-level grot */ -int portof(const ip_address *src); -void setportof(int port, ip_address *dst); -struct sockaddr *sockaddrof(ip_address *src); -size_t sockaddrlenof(const ip_address *src); - -/* odds and ends */ -const char **ipsec_copyright_notice(void); - -const char *dns_string_rr(int rr, char *buf, int bufsize); -const char *dns_string_datetime(time_t seconds, - char *buf, - int bufsize); - - -/* - * old functions, to be deleted eventually - */ - -/* unsigned long */ -const char * /* NULL for success, else string literal */ -atoul( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - int base, /* 0 means figure it out */ - unsigned long *resultp -); -size_t /* space needed for full conversion */ -ultoa( - unsigned long n, - int base, - char *dst, - size_t dstlen -); -#define ULTOA_BUF 21 /* just large enough for largest result, */ - /* assuming 64-bit unsigned long! */ - -/* Internet addresses */ -const char * /* NULL for success, else string literal */ -atoaddr( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - struct in_addr *addr -); -size_t /* space needed for full conversion */ -addrtoa( - struct in_addr addr, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define ADDRTOA_BUF 16 /* just large enough for largest result */ - -/* subnets */ -const char * /* NULL for success, else string literal */ -atosubnet( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - struct in_addr *addr, - struct in_addr *mask -); -size_t /* space needed for full conversion */ -subnettoa( - struct in_addr addr, - struct in_addr mask, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define SUBNETTOA_BUF 32 /* large enough for worst case result */ - -/* ranges */ -const char * /* NULL for success, else string literal */ -atoasr( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *type, /* 'a', 's', 'r' */ - struct in_addr *addrs /* two-element array */ -); -size_t /* space needed for full conversion */ -rangetoa( - struct in_addr *addrs, /* two-element array */ - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); -#define RANGETOA_BUF 34 /* large enough for worst case result */ - -/* generic data, e.g. keys */ -const char * /* NULL for success, else string literal */ -atobytes( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *dst, - size_t dstlen, - size_t *lenp /* NULL means don't bother telling me */ -); -size_t /* 0 failure, else true size */ -bytestoa( - const char *src, - size_t srclen, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); - -/* old versions of generic-data functions; deprecated */ -size_t /* 0 failure, else true size */ -atodata( - const char *src, - size_t srclen, /* 0 means strlen(src) */ - char *dst, - size_t dstlen -); -size_t /* 0 failure, else true size */ -datatoa( - const char *src, - size_t srclen, - int format, /* character; 0 means default */ - char *dst, - size_t dstlen -); - -/* part extraction and special addresses */ -struct in_addr -subnetof( - struct in_addr addr, - struct in_addr mask -); -struct in_addr -hostof( - struct in_addr addr, - struct in_addr mask -); -struct in_addr -broadcastof( - struct in_addr addr, - struct in_addr mask -); - -/* mask handling */ -int -goodmask( - struct in_addr mask -); -int -masktobits( - struct in_addr mask -); -struct in_addr -bitstomask( - int n -); - -/* - * Debugging levels for pfkey_lib_debug - */ -#define PF_KEY_DEBUG_PARSE_NONE 0 -#define PF_KEY_DEBUG_PARSE_PROBLEM 1 -#define PF_KEY_DEBUG_PARSE_STRUCT 2 -#define PF_KEY_DEBUG_PARSE_FLOW 4 -#define PF_KEY_DEBUG_PARSE_MAX 7 - -extern unsigned int pfkey_lib_debug; /* bits selecting what to report */ - -/* - * pluto and lwdnsq need to know the maximum size of the commands to, - * and replies from lwdnsq. - */ - -#define LWDNSQ_CMDBUF_LEN 1024 -#define LWDNSQ_RESULT_LEN_MAX 4096 - -#endif /* _FREESWAN_H */ diff --git a/src/libfreeswan/goodmask.3 b/src/libfreeswan/goodmask.3 deleted file mode 100644 index b76d431ca..000000000 --- a/src/libfreeswan/goodmask.3 +++ /dev/null @@ -1,56 +0,0 @@ -.TH IPSEC_GOODMASK 3 "11 June 2001" -.SH NAME -ipsec goodmask \- is this Internet subnet mask a valid one? -.br -ipsec masktobits \- convert Internet subnet mask to bit count -.br -ipsec bitstomask \- convert bit count to Internet subnet mask -.SH SYNOPSIS -.B "#include -.sp -.B "int goodmask(struct in_addr mask);" -.br -.B "int masktobits(struct in_addr mask);" -.br -.B "struct in_addr bitstomask(int n);" -.SH DESCRIPTION -These functions are obsolete; -see -.IR ipsec_masktocount (3) -for a partial replacement. -.PP -.I Goodmask -reports whether the subnet -.I mask -is a valid one, -i.e. consists of a (possibly empty) sequence of -.BR 1 s -followed by a (possibly empty) sequence of -.BR 0 s. -.I Masktobits -takes a (valid) subnet mask and returns the number of -.B 1 -bits in it. -.I Bitstomask -reverses this, -returning the subnet mask corresponding to bit count -.IR n . -.PP -All masks are in network byte order. -.SH SEE ALSO -inet(3), ipsec_atosubnet(3) -.SH DIAGNOSTICS -.I Masktobits -returns -.B \-1 -for an invalid mask. -.I Bitstomask -returns an all-zeros mask for a negative or out-of-range -.IR n . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The error-reporting convention of -.I bitstomask -is less than ideal; -zero is sometimes a legitimate mask. diff --git a/src/libfreeswan/goodmask.c b/src/libfreeswan/goodmask.c deleted file mode 100644 index 66edae20f..000000000 --- a/src/libfreeswan/goodmask.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * minor utilities for subnet-mask manipulation - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - goodmask - is this a good (^1*0*$) subnet mask? - * You are not expected to understand this. See Henry S. Warren Jr, - * "Functions realizable with word-parallel logical and two's-complement - * addition instructions", CACM 20.6 (June 1977), p.439. - */ -int /* predicate */ -goodmask(mask) -struct in_addr mask; -{ - unsigned long x = ntohl(mask.s_addr); - /* clear rightmost contiguous string of 1-bits */ -# define CRCS1B(x) (((x|(x-1))+1)&x) -# define TOPBIT (1UL << 31) - - /* either zero, or has one string of 1-bits which is left-justified */ - if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT))) - return 1; - return 0; -} - -/* - - masktobits - how many bits in this mask? - * The algorithm is essentially a binary search, but highly optimized - * for this particular task. - */ -int /* -1 means !goodmask() */ -masktobits(mask) -struct in_addr mask; -{ - unsigned long m = ntohl(mask.s_addr); - int masklen; - - if (!goodmask(mask)) - return -1; - - if (m&0x00000001UL) - return 32; - masklen = 0; - if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */ - masklen |= 0x10; - m <<= 16; - } - if (m&(0x00ff0000UL<<1)) { - masklen |= 0x08; - m <<= 8; - } - if (m&(0x0f000000UL<<1)) { - masklen |= 0x04; - m <<= 4; - } - if (m&(0x30000000UL<<1)) { - masklen |= 0x02; - m <<= 2; - } - if (m&(0x40000000UL<<1)) - masklen |= 0x01; - - return masklen; -} - -/* - - bitstomask - return a mask with this many high bits on - */ -struct in_addr -bitstomask(n) -int n; -{ - struct in_addr result; - - if (n > 0 && n <= ABITS) - result.s_addr = htonl(~((1UL << (ABITS - n)) - 1)); - else if (n == 0) - result.s_addr = 0; - else - result.s_addr = 0; /* best error report we can do */ - return result; -} diff --git a/src/libfreeswan/initaddr.3 b/src/libfreeswan/initaddr.3 deleted file mode 100644 index 071e507aa..000000000 --- a/src/libfreeswan/initaddr.3 +++ /dev/null @@ -1,128 +0,0 @@ -.TH IPSEC_INITADDR 3 "11 Sept 2000" -.SH NAME -ipsec initaddr \- initialize an ip_address -.br -ipsec addrtypeof \- get address type of an ip_address -.br -ipsec addrlenof \- get length of address within an ip_address -.br -ipsec addrbytesof \- get copy of address within an ip_address -.br -ipsec addrbytesptr \- get pointer to address within an ip_address -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *initaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *dst);" -.br -.B "int addrtypeof(const ip_address *src);" -.br -.B "size_t addrlenof(const ip_address *src);" -.br -.B "size_t addrbytesof(const ip_address *src," -.ti +1c -.B "unsigned char *dst, size_t dstlen);" -.br -.B "size_t addrbytesptr(const ip_address *src," -.ti +1c -.B "const unsigned char **dst);" -.SH DESCRIPTION -The -.B -library uses an internal type -.I ip_address -to contain one of the (currently two) types of IP address. -These functions provide basic tools for creating and examining this type. -.PP -.I Initaddr -initializes a variable -.I *dst -of type -.I ip_address -from an address -(in network byte order, -indicated by a pointer -.I src -and a length -.IR srclen ) -and an address family -.I af -(typically -.B AF_INET -or -.BR AF_INET6 ). -The length must be consistent with the address family. -.PP -.I Addrtypeof -returns the address type of an address, -normally -.B AF_INET -or -.BR AF_INET6 . -(The -.B -header file arranges to include the necessary headers for these -names to be known.) -.PP -.I Addrlenof -returns the size (in bytes) of the address within an -.IR ip_address , -to permit storage allocation etc. -.PP -.I Addrbytesof -copies the address within the -.I ip_address -.I src -to the buffer indicated by the pointer -.I dst -and the length -.IR dstlen , -and returns the address length (in bytes). -If the address will not fit, -as many bytes as will fit are copied; -the returned length is still the full length. -It is the caller's responsibility to check the -returned value to ensure that there was enough room. -.PP -.I Addrbytesptr -sets -.I *dst -to a pointer to the internal address within the -.IR ip_address , -and returns the address length (in bytes). -If -.I dst -is -.BR NULL , -it just returns the address length. -The pointer points to -.B const -to discourage misuse. -.PP -.I Initaddr -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.PP -The functions which return -.I size_t -return -.B 0 -for a failure. -.SH SEE ALSO -inet(3), ipsec_ttoaddr(3) -.SH DIAGNOSTICS -An unknown address family is a fatal error for any of these functions -except -.IR addrtypeof . -An address-size mismatch is a fatal error for -.IR initaddr . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -.I Addrtypeof -should probably have been named -.IR addrfamilyof . diff --git a/src/libfreeswan/initaddr.c b/src/libfreeswan/initaddr.c deleted file mode 100644 index c84006f47..000000000 --- a/src/libfreeswan/initaddr.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * initialize address structure - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - initaddr - initialize ip_address from bytes - */ -err_t /* NULL for success, else string literal */ -initaddr(src, srclen, af, dst) -const unsigned char *src; -size_t srclen; -int af; /* address family */ -ip_address *dst; -{ - switch (af) { - case AF_INET: - if (srclen != 4) - return "IPv4 address must be exactly 4 bytes"; - dst->u.v4.sin_family = af; - dst->u.v4.sin_port = 0; /* unused */ - memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen); - break; - case AF_INET6: - if (srclen != 16) - return "IPv6 address must be exactly 16 bytes"; - dst->u.v6.sin6_family = af; - dst->u.v6.sin6_flowinfo = 0; /* unused */ - dst->u.v6.sin6_port = 0; /* unused */ - memcpy((char *)&dst->u.v6.sin6_addr, src, srclen); - break; - default: - return "unknown address family in initaddr"; - break; - } - return NULL; -} diff --git a/src/libfreeswan/initsaid.c b/src/libfreeswan/initsaid.c deleted file mode 100644 index 4e4bc9a35..000000000 --- a/src/libfreeswan/initsaid.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * initialize SA ID structure - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - initsaid - initialize SA ID from bits - */ -void -initsaid(addr, spi, proto, dst) -const ip_address *addr; -ipsec_spi_t spi; -int proto; -ip_said *dst; -{ - dst->dst = *addr; - dst->spi = spi; - dst->proto = proto; -} diff --git a/src/libfreeswan/initsubnet.3 b/src/libfreeswan/initsubnet.3 deleted file mode 100644 index 3545fd426..000000000 --- a/src/libfreeswan/initsubnet.3 +++ /dev/null @@ -1,136 +0,0 @@ -.TH IPSEC_INITSUBNET 3 "12 March 2002" -.SH NAME -ipsec initsubnet \- initialize an ip_subnet -.br -ipsec addrtosubnet \- initialize a singleton ip_subnet -.br -ipsec subnettypeof \- get address type of an ip_subnet -.br -ipsec masktocount \- convert subnet mask to bit count -.br -ipsec networkof \- get base address of an ip_subnet -.br -ipsec maskof \- get subnet mask of an ip_subnet -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *initsubnet(const ip_address *addr," -.ti +1c -.B "int maskbits, int clash, ip_subnet *dst);" -.br -.B "const char *addrtosubnet(const ip_address *addr," -.ti +1c -.B "ip_subnet *dst);" -.sp -.B "int subnettypeof(const ip_subnet *src);" -.br -.B "int masktocount(const ip_address *src);" -.br -.B "void networkof(const ip_subnet *src, ip_address *dst);" -.br -.B "void maskof(const ip_subnet *src, ip_address *dst);" -.SH DESCRIPTION -The -.B -library uses an internal type -.I ip_subnet -to contain a description of an IP subnet -(base address plus mask). -These functions provide basic tools for creating and examining this type. -.PP -.I Initsubnet -initializes a variable -.I *dst -of type -.I ip_subnet -from a base address and -a count of mask bits. -The -.I clash -parameter specifies what to do if the base address includes -.B 1 -bits outside the prefix specified by the mask -(that is, in the ``host number'' part of the address): -.RS -.IP '0' 5 -zero out host-number bits -.IP 'x' -non-zero host-number bits are an error -.RE -.PP -.I Initsubnet -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.PP -.I Addrtosubnet -initializes an -.I ip_subnet -variable -.I *dst -to a ``singleton subnet'' containing the single address -.IR *addr . -It returns -.B NULL -for success and -a pointer to a string-literal error message for failure. -.PP -.I Subnettypeof -returns the address type of a subnet, -normally -.B AF_INET -or -.BR AF_INET6 . -(The -.B -header file arranges to include the necessary headers for these -names to be known.) -.PP -.I Masktocount -converts a subnet mask, expressed as an address, to a bit count -suitable for use with -.IR initsubnet . -It returns -.B \-1 -for error; see DIAGNOSTICS. -.PP -.I Networkof -fills in -.I *dst -with the base address of subnet -.IR src . -.PP -.I Maskof -fills in -.I *dst -with the subnet mask of subnet -.IR src , -expressed as an address. -.SH SEE ALSO -inet(3), ipsec_ttosubnet(3), ipsec_rangetosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I initsubnet -are: -unknown address family; -unknown -.I clash -value; -impossible mask bit count; -non-zero host-number bits and -.I clash -is -.BR 'x' . -Fatal errors in -.I addrtosubnet -are: -unknown address family. -Fatal errors in -.I masktocount -are: -unknown address family; -mask bits not contiguous. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/initsubnet.c b/src/libfreeswan/initsubnet.c deleted file mode 100644 index 27faddabc..000000000 --- a/src/libfreeswan/initsubnet.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * initialize subnet structure - * Copyright (C) 2000, 2002 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - initsubnet - initialize ip_subnet from address and count - * - * The only hard part is checking for host-part bits turned on. - */ -err_t /* NULL for success, else string literal */ -initsubnet(addr, count, clash, dst) -const ip_address *addr; -int count; -int clash; /* '0' zero host-part bits, 'x' die on them */ -ip_subnet *dst; -{ - unsigned char *p; - int n; - int c; - unsigned m; - int die; - - dst->addr = *addr; - n = addrbytesptr(&dst->addr, (const unsigned char **)&p); - if (n == 0) - return "unknown address family"; - - switch (clash) { - case '0': - die = 0; - break; - case 'x': - die = 1; - break; - default: - return "unknown clash-control value in initsubnet"; - break; - } - - c = count / 8; - if (c > n) - return "impossible mask count"; - p += c; - n -= c; - - m = 0xff; - c = count % 8; - if (n > 0 && c != 0) /* partial byte */ - m >>= c; - for (; n > 0; n--) { - if ((*p & m) != 0) { - if (die) - return "improper subnet, host-part bits on"; - *p &= ~m; - } - m = 0xff; - p++; - } - - dst->maskbits = count; - return NULL; -} - -/* - - addrtosubnet - initialize ip_subnet from a single address - */ -err_t /* NULL for success, else string literal */ -addrtosubnet(addr, dst) -const ip_address *addr; -ip_subnet *dst; -{ - int n; - - dst->addr = *addr; - n = addrbytesptr(&dst->addr, (const unsigned char **)NULL); - if (n == 0) - return "unknown address family"; - dst->maskbits = n*8; - return NULL; -} diff --git a/src/libfreeswan/internal.h b/src/libfreeswan/internal.h deleted file mode 100644 index 832c8a53d..000000000 --- a/src/libfreeswan/internal.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * internal definitions for use within the library; do not export! - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ - -#ifndef ABITS -#define ABITS 32 /* bits in an IPv4 address */ -#endif - -/* case-independent ASCII character equality comparison */ -#define CIEQ(c1, c2) ( ((c1)&~040) == ((c2)&~040) ) - -/* syntax for passthrough SA */ -#ifndef PASSTHROUGHNAME -#define PASSTHROUGHNAME "%passthrough" -#define PASSTHROUGH4NAME "%passthrough4" -#define PASSTHROUGH6NAME "%passthrough6" -#define PASSTHROUGHIS "tun0@0.0.0.0" -#define PASSTHROUGH4IS "tun0@0.0.0.0" -#define PASSTHROUGH6IS "tun0@::" -#define PASSTHROUGHTYPE "tun" -#define PASSTHROUGHSPI 0 -#define PASSTHROUGHDST 0 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#define MALLOC(n) malloc(n) -#define FREE(p) free(p) - diff --git a/src/libfreeswan/ipsec_param.h b/src/libfreeswan/ipsec_param.h deleted file mode 100644 index 93426b8ee..000000000 --- a/src/libfreeswan/ipsec_param.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * @(#) FreeSWAN tunable paramaters - * - * Copyright (C) 2001 Richard Guy Briggs - * and Michael Richardson - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * This file provides a set of #define's which may be tuned by various - * people/configurations. It keeps all compile-time tunables in one place. - * - * This file should be included before all other IPsec kernel-only files. - * - */ - -#ifndef _IPSEC_PARAM_H_ - -/* - * This is for the SA reference table. This number is related to the - * maximum number of SAs that KLIPS can concurrently deal with, plus enough - * space for keeping expired SAs around. - * - * TABLE_MAX_WIDTH is the number of bits that we will use. - * MAIN_TABLE_WIDTH is the number of bits used for the primary index table. - * - */ -#ifndef IPSEC_SA_REF_TABLE_IDX_WIDTH -# define IPSEC_SA_REF_TABLE_IDX_WIDTH 16 -#endif - -#ifndef IPSEC_SA_REF_MAINTABLE_IDX_WIDTH -# define IPSEC_SA_REF_MAINTABLE_IDX_WIDTH 4 -#endif - -#ifndef IPSEC_SA_REF_FREELIST_NUM_ENTRIES -# define IPSEC_SA_REF_FREELIST_NUM_ENTRIES 256 -#endif - -#ifndef IPSEC_SA_REF_CODE -# define IPSEC_SA_REF_CODE 1 -#endif - -#define _IPSEC_PARAM_H_ -#endif /* _IPSEC_PARAM_H_ */ diff --git a/src/libfreeswan/pfkey.h b/src/libfreeswan/pfkey.h deleted file mode 100644 index 993678c8b..000000000 --- a/src/libfreeswan/pfkey.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * FreeS/WAN specific PF_KEY headers - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef __NET_IPSEC_PF_KEY_H -#define __NET_IPSEC_PF_KEY_H - -extern void (*pfkey_debug_func)(const char *message, ...); - -extern uint8_t satype2proto(uint8_t satype); -extern uint8_t proto2satype(uint8_t proto); -extern char* satype2name(uint8_t satype); -extern char* proto2name(uint8_t proto); - -struct key_opt -{ - uint32_t key_pid; /* process ID */ - struct sock *sk; -}; - -#define key_pid(sk) ((struct key_opt*)&((sk)->protinfo))->key_pid - -#define IPSEC_PFKEYv2_ALIGN (sizeof(uint64_t)/sizeof(uint8_t)) -#define BITS_PER_OCTET 8 -#define OCTETBITS 8 -#define PFKEYBITS 64 -#define DIVUP(x,y) ((x + y -1) / y) /* divide, rounding upwards */ -#define ALIGN_N(x,y) (DIVUP(x,y) * y) /* align on y boundary */ - -#define PFKEYv2_MAX_MSGSIZE 4096 - -/* - * PF_KEYv2 permitted and required extensions in and out bitmaps - */ -struct pf_key_ext_parsers_def { - int (*parser)(struct sadb_ext*); - char *parser_name; -}; - - -extern unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/]; -#define EXT_BITS_IN 0 -#define EXT_BITS_OUT 1 -#define EXT_BITS_PERM 0 -#define EXT_BITS_REQ 1 - -extern void pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]); -extern void pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]); -extern void pfkey_msg_free(struct sadb_msg **pfkey_msg); - -extern int pfkey_msg_parse(struct sadb_msg *pfkey_msg, - struct pf_key_ext_parsers_def *ext_parsers[], - struct sadb_ext **extensions, - int dir); - -/* - * PF_KEYv2 build function prototypes - */ - -int -pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext, - uint8_t msg_type, - uint8_t satype, - uint8_t msg_errno, - uint32_t seq, - uint32_t pid); - -int -pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, /* in network order */ - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags, - uint32_t/*IPsecSAref_t*/ ref); - -int -pfkey_sa_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, /* in network order */ - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags); - -int -pfkey_lifetime_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t allocations, - uint64_t bytes, - uint64_t addtime, - uint64_t usetime, - uint32_t packets); - -int -pfkey_address_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint8_t proto, - uint8_t prefixlen, - struct sockaddr* address); - -int -pfkey_key_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t key_bits, - char* key); - -int -pfkey_ident_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t ident_type, - uint64_t ident_id, - uint8_t ident_len, - char* ident_string); - -int -pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext, - uint8_t type); -int -pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t port); - -int -pfkey_sens_build(struct sadb_ext** pfkey_ext, - uint32_t dpd, - uint8_t sens_level, - uint8_t sens_len, - uint64_t* sens_bitmap, - uint8_t integ_level, - uint8_t integ_len, - uint64_t* integ_bitmap); - -int -pfkey_x_protocol_build(struct sadb_ext **, uint8_t); - - -int -pfkey_prop_build(struct sadb_ext** pfkey_ext, - uint8_t replay, - unsigned int comb_num, - struct sadb_comb* comb); - -int -pfkey_supported_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - unsigned int alg_num, - struct sadb_alg* alg); - -int -pfkey_spirange_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint32_t min, - uint32_t max); - -int -pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext); - -int -pfkey_x_satype_build(struct sadb_ext** pfkey_ext, - uint8_t satype); - -int -pfkey_x_debug_build(struct sadb_ext** pfkey_ext, - uint32_t tunnel, - uint32_t netlink, - uint32_t xform, - uint32_t eroute, - uint32_t spi, - uint32_t radij, - uint32_t esp, - uint32_t ah, - uint32_t rcv, - uint32_t pfkey, - uint32_t ipcomp, - uint32_t verbose); - -int -pfkey_msg_build(struct sadb_msg** pfkey_msg, - struct sadb_ext* extensions[], - int dir); - -/* in pfkey_v2_debug.c - routines to decode numbers -> strings */ -const char * -pfkey_v2_sadb_ext_string(int extnum); - -const char * -pfkey_v2_sadb_type_string(int sadb_type); - - -#endif /* __NET_IPSEC_PF_KEY_H */ diff --git a/src/libfreeswan/pfkey_v2_build.c b/src/libfreeswan/pfkey_v2_build.c deleted file mode 100644 index c0bb369cb..000000000 --- a/src/libfreeswan/pfkey_v2_build.c +++ /dev/null @@ -1,1388 +0,0 @@ -/* - * RFC2367 PF_KEYv2 Key management API message parser - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parser.c. - */ - -char pfkey_v2_build_c_version[] = ""; - -# include -# include -# include -# include -# include /* memset */ - -# include -unsigned int pfkey_lib_debug = 0; - -void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1); - -#define DEBUGGING(args...) if(pfkey_lib_debug) { \ - if(pfkey_debug_func != NULL) { \ - (*pfkey_debug_func)("pfkey_lib_debug:" args); \ - } else { \ - printf("pfkey_lib_debug:" args); \ - } } -# define MALLOC(size) malloc(size) -# define FREE(obj) free(obj) - -#include -#include - -#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) - -void -pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - int i; - - for (i = 0; i != SADB_EXT_MAX + 1; i++) { - extensions[i] = NULL; - } -} - -void -pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - int i; - - if (!extensions) { - return; - } - - if (extensions[0]) { - memset(extensions[0], 0, sizeof(struct sadb_msg)); - FREE(extensions[0]); - extensions[0] = NULL; - } - - for (i = 1; i != SADB_EXT_MAX + 1; i++) { - if(extensions[i]) { - memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - FREE(extensions[i]); - extensions[i] = NULL; - } - } -} - -void -pfkey_msg_free(struct sadb_msg **pfkey_msg) -{ - if (*pfkey_msg) { - memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN); - FREE(*pfkey_msg); - *pfkey_msg = NULL; - } -} - -/* Default extension builders taken from the KLIPS code */ - -int -pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext, - uint8_t msg_type, - uint8_t satype, - uint8_t msg_errno, - uint32_t seq, - uint32_t pid) -{ - int error = 0; - struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext; - - DEBUGGING( - "pfkey_msg_hdr_build:\n"); - DEBUGGING( - "pfkey_msg_hdr_build: " - "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n", - &pfkey_ext, - pfkey_ext, - *pfkey_ext); - /* sanity checks... */ - if (pfkey_msg) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "why is pfkey_msg already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!msg_type) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "msg type not set, must be non-zero..\n"); - SENDERR(EINVAL); - } - - if (msg_type > SADB_MAX) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "msg type too large:%d.\n", - msg_type); - SENDERR(EINVAL); - } - - if (satype > SADB_SATYPE_MAX) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "satype %d > max %d\n", - satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg)); - *pfkey_ext = (struct sadb_ext*)pfkey_msg; - - if (pfkey_msg == NULL) { - DEBUGGING( - "pfkey_msg_hdr_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_msg, 0, sizeof(struct sadb_msg)); - - pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - - pfkey_msg->sadb_msg_type = msg_type; - pfkey_msg->sadb_msg_satype = satype; - - pfkey_msg->sadb_msg_version = PF_KEY_V2; - pfkey_msg->sadb_msg_errno = msg_errno; - pfkey_msg->sadb_msg_reserved = 0; - pfkey_msg->sadb_msg_seq = seq; - pfkey_msg->sadb_msg_pid = pid; - DEBUGGING( - "pfkey_msg_hdr_build: " - "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n", - &pfkey_ext, - pfkey_ext, - *pfkey_ext); -errlab: - return error; -} - -int -pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags, - uint32_t/*IPsecSAref_t*/ ref) -{ - int error = 0; - struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext; - - DEBUGGING( - "pfkey_sa_build: " - "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n", - ntohl(spi), /* in network order */ - replay_window, - sa_state, - auth, - encrypt, - flags); - /* sanity checks... */ - if (pfkey_sa) { - DEBUGGING( - "pfkey_sa_build: " - "why is pfkey_sa already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (exttype != SADB_EXT_SA - && exttype != SADB_X_EXT_SA2) { - DEBUGGING( - "pfkey_sa_build: " - "invalid exttype=%d.\n", - exttype); - SENDERR(EINVAL); - } - - if (replay_window > 64) { - DEBUGGING( - "pfkey_sa_build: " - "replay window size: %d -- must be 0 <= size <= 64\n", - replay_window); - SENDERR(EINVAL); - } - - if (auth > SADB_AALG_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "auth=%d > SADB_AALG_MAX=%d.\n", - auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if (encrypt > SADB_EALG_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "encrypt=%d > SADB_EALG_MAX=%d.\n", - encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if (sa_state > SADB_SASTATE_MAX) { - DEBUGGING( - "pfkey_sa_build: " - "sa_state=%d exceeds MAX=%d.\n", - sa_state, - SADB_SASTATE_MAX); - SENDERR(EINVAL); - } - - if (sa_state == SADB_SASTATE_DEAD) { - DEBUGGING( - "pfkey_sa_build: " - "sa_state=%d is DEAD=%d is not allowed.\n", - sa_state, - SADB_SASTATE_DEAD); - SENDERR(EINVAL); - } - - if ((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) { - DEBUGGING( - "pfkey_sa_build: " - "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n", - ref, - IPSEC_SAREF_NULL, - IPSEC_SA_REF_TABLE_NUM_ENTRIES); - SENDERR(EINVAL); - } - - pfkey_sa = (struct sadb_sa*)MALLOC(sizeof(struct sadb_sa)); - *pfkey_ext = (struct sadb_ext*)pfkey_sa; - - if (pfkey_sa == NULL) { - DEBUGGING( - "pfkey_sa_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_sa, 0, sizeof(struct sadb_sa)); - - pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN; - pfkey_sa->sadb_sa_exttype = exttype; - pfkey_sa->sadb_sa_spi = spi; - pfkey_sa->sadb_sa_replay = replay_window; - pfkey_sa->sadb_sa_state = sa_state; - pfkey_sa->sadb_sa_auth = auth; - pfkey_sa->sadb_sa_encrypt = encrypt; - pfkey_sa->sadb_sa_flags = flags; - pfkey_sa->sadb_x_sa_ref = ref; - -errlab: - return error; -} - -int -pfkey_sa_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t spi, - uint8_t replay_window, - uint8_t sa_state, - uint8_t auth, - uint8_t encrypt, - uint32_t flags) -{ - return pfkey_sa_ref_build(pfkey_ext, - exttype, - spi, - replay_window, - sa_state, - auth, - encrypt, - flags, - IPSEC_SAREF_NULL); -} - -int -pfkey_lifetime_build(struct sadb_ext ** pfkey_ext, - uint16_t exttype, - uint32_t allocations, - uint64_t bytes, - uint64_t addtime, - uint64_t usetime, - uint32_t packets) -{ - int error = 0; - struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext; - - DEBUGGING( - "pfkey_lifetime_build:\n"); - /* sanity checks... */ - if (pfkey_lifetime) { - DEBUGGING( - "pfkey_lifetime_build: " - "why is pfkey_lifetime already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (exttype != SADB_EXT_LIFETIME_CURRENT - && exttype != SADB_EXT_LIFETIME_HARD - && exttype != SADB_EXT_LIFETIME_SOFT) { - DEBUGGING( - "pfkey_lifetime_build: " - "invalid exttype=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime)); - *pfkey_ext = (struct sadb_ext*)pfkey_lifetime; - - if (pfkey_lifetime == NULL) { - DEBUGGING( - "pfkey_lifetime_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime)); - - pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN; - pfkey_lifetime->sadb_lifetime_exttype = exttype; - pfkey_lifetime->sadb_lifetime_allocations = allocations; - pfkey_lifetime->sadb_lifetime_bytes = bytes; - pfkey_lifetime->sadb_lifetime_addtime = addtime; - pfkey_lifetime->sadb_lifetime_usetime = usetime; - pfkey_lifetime->sadb_x_lifetime_packets = packets; - -errlab: - return error; -} - -int -pfkey_address_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint8_t proto, - uint8_t prefixlen, - struct sockaddr* address) -{ - int error = 0; - int saddr_len = 0; - char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/]; - struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext; - - DEBUGGING( - "pfkey_address_build: " - "exttype=%d proto=%d prefixlen=%d\n", - exttype, - proto, - prefixlen); - /* sanity checks... */ - if (pfkey_address) { - DEBUGGING( - "pfkey_address_build: " - "why is pfkey_address already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!address) { - DEBUGGING("pfkey_address_build: " - "address is NULL\n"); - SENDERR(EINVAL); - } - - switch(exttype) { - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - case SADB_X_EXT_ADDRESS_DST2: - case SADB_X_EXT_ADDRESS_SRC_FLOW: - case SADB_X_EXT_ADDRESS_DST_FLOW: - case SADB_X_EXT_ADDRESS_SRC_MASK: - case SADB_X_EXT_ADDRESS_DST_MASK: - case SADB_X_EXT_NAT_T_OA: - break; - default: - DEBUGGING( - "pfkey_address_build: " - "unrecognised ext_type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - switch (address->sa_family) { - case AF_INET: - DEBUGGING( - "pfkey_address_build: " - "found address family AF_INET.\n"); - saddr_len = sizeof(struct sockaddr_in); - sprintf(ipaddr_txt, "%d.%d.%d.%d:%d" - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF - , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF - , ntohs(((struct sockaddr_in*)address)->sin_port)); - break; - case AF_INET6: - DEBUGGING( - "pfkey_address_build: " - "found address family AF_INET6.\n"); - saddr_len = sizeof(struct sockaddr_in6); - sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x" - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[0]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[1]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[2]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[3]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[4]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[5]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[6]) - , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr[7]) - , ntohs(((struct sockaddr_in6*)address)->sin6_port)); - break; - default: - DEBUGGING( - "pfkey_address_build: " - "address->sa_family=%d not supported.\n", - address->sa_family); - SENDERR(EPFNOSUPPORT); - } - - DEBUGGING( - "pfkey_address_build: " - "found address=%s.\n", - ipaddr_txt); - if (prefixlen != 0) { - DEBUGGING( - "pfkey_address_build: " - "address prefixes not supported yet.\n"); - SENDERR(EAFNOSUPPORT); /* not supported yet */ - } - - pfkey_address = (struct sadb_address*) - MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)); - *pfkey_ext = (struct sadb_ext*)pfkey_address; - - if (pfkey_address == NULL) { - DEBUGGING( - "pfkey_lifetime_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_address, - 0, - ALIGN_N(sizeof(struct sadb_address) + saddr_len, - IPSEC_PFKEYv2_ALIGN)); - - pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len, - IPSEC_PFKEYv2_ALIGN); - - pfkey_address->sadb_address_exttype = exttype; - pfkey_address->sadb_address_proto = proto; - pfkey_address->sadb_address_prefixlen = prefixlen; - pfkey_address->sadb_address_reserved = 0; - - memcpy((char*)pfkey_address + sizeof(struct sadb_address), - address, - saddr_len); - -#if 0 - for (i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) { - pfkey_address_s_ska.sin_zero[i] = 0; - } -#endif - DEBUGGING( - "pfkey_address_build: " - "successful.\n"); - - errlab: - return error; -} - -int -pfkey_key_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t key_bits, - char* key) -{ - int error = 0; - struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext; - - DEBUGGING( - "pfkey_key_build:\n"); - /* sanity checks... */ - if (pfkey_key) { - DEBUGGING( - "pfkey_key_build: " - "why is pfkey_key already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!key_bits) { - DEBUGGING( - "pfkey_key_build: " - "key_bits is zero, it must be non-zero.\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) { - DEBUGGING( - "pfkey_key_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_key = (struct sadb_key*) - MALLOC(sizeof(struct sadb_key) + - DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN); - *pfkey_ext = (struct sadb_ext*)pfkey_key; - - if (pfkey_key == NULL) { - DEBUGGING( - "pfkey_key_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_key, - 0, - sizeof(struct sadb_key) + - DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN); - - pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits, - 64); - pfkey_key->sadb_key_exttype = exttype; - pfkey_key->sadb_key_bits = key_bits; - pfkey_key->sadb_key_reserved = 0; - memcpy((char*)pfkey_key + sizeof(struct sadb_key), - key, - DIVUP(key_bits, 8)); - -errlab: - return error; -} - -int -pfkey_ident_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t ident_type, - uint64_t ident_id, - uint8_t ident_len, - char* ident_string) -{ - int error = 0; - struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext; - int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident); - - DEBUGGING( - "pfkey_ident_build:\n"); - /* sanity checks... */ - if (pfkey_ident) { - DEBUGGING( - "pfkey_ident_build: " - "why is pfkey_ident already pointing to something?\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_IDENTITY_SRC) || - (exttype == SADB_EXT_IDENTITY_DST))) { - DEBUGGING( - "pfkey_ident_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - if (ident_type == SADB_IDENTTYPE_RESERVED) { - DEBUGGING( - "pfkey_ident_build: " - "ident_type must be non-zero.\n"); - SENDERR(EINVAL); - } - - if (ident_type > SADB_IDENTTYPE_MAX) { - DEBUGGING( - "pfkey_ident_build: " - "identtype=%d out of range.\n", - ident_type); - SENDERR(EINVAL); - } - - if ((ident_type == SADB_IDENTTYPE_PREFIX || - ident_type == SADB_IDENTTYPE_FQDN) && - !ident_string) { - DEBUGGING( - "pfkey_ident_build: " - "string required to allocate size of extension.\n"); - SENDERR(EINVAL); - } - -#if 0 - if (ident_type == SADB_IDENTTYPE_USERFQDN) { - } -#endif - - pfkey_ident = (struct sadb_ident*) - MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN); - *pfkey_ext = (struct sadb_ext*)pfkey_ident; - - if (pfkey_ident == NULL) { - DEBUGGING( - "pfkey_ident_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN); - - pfkey_ident->sadb_ident_len = ident_len; - pfkey_ident->sadb_ident_exttype = exttype; - pfkey_ident->sadb_ident_type = ident_type; - pfkey_ident->sadb_ident_reserved = 0; - pfkey_ident->sadb_ident_id = ident_id; - memcpy((char*)pfkey_ident + sizeof(struct sadb_ident), - ident_string, - data_len); - -errlab: - return error; -} - -int -pfkey_sens_build(struct sadb_ext** pfkey_ext, - uint32_t dpd, - uint8_t sens_level, - uint8_t sens_len, - uint64_t* sens_bitmap, - uint8_t integ_level, - uint8_t integ_len, - uint64_t* integ_bitmap) -{ - int error = 0; - struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext; - int i; - uint64_t* bitmap; - - DEBUGGING( - "pfkey_sens_build:\n"); - /* sanity checks... */ - if (pfkey_sens) { - DEBUGGING( - "pfkey_sens_build: " - "why is pfkey_sens already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_sens_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - pfkey_sens = (struct sadb_sens*) - MALLOC(sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)); - *pfkey_ext = (struct sadb_ext*)pfkey_sens; - - if (pfkey_sens == NULL) { - DEBUGGING( - "pfkey_sens_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_sens, - 0, - sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)); - - pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) + - (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN; - pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY; - pfkey_sens->sadb_sens_dpd = dpd; - pfkey_sens->sadb_sens_sens_level = sens_level; - pfkey_sens->sadb_sens_sens_len = sens_len; - pfkey_sens->sadb_sens_integ_level = integ_level; - pfkey_sens->sadb_sens_integ_len = integ_len; - pfkey_sens->sadb_sens_reserved = 0; - - bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens)); - for (i = 0; i < sens_len; i++) { - *bitmap = sens_bitmap[i]; - bitmap++; - } - for (i = 0; i < integ_len; i++) { - *bitmap = integ_bitmap[i]; - bitmap++; - } - -errlab: - return error; -} - -int -pfkey_prop_build(struct sadb_ext** pfkey_ext, - uint8_t replay, - unsigned int comb_num, - struct sadb_comb* comb) -{ - int error = 0; - int i; - struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext; - struct sadb_comb *combp; - - DEBUGGING( - "pfkey_prop_build:\n"); - /* sanity checks... */ - if (pfkey_prop) { - DEBUGGING( - "pfkey_prop_build: " - "why is pfkey_prop already pointing to something?\n"); - SENDERR(EINVAL); - } - - pfkey_prop = (struct sadb_prop*) - MALLOC(sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)); - - *pfkey_ext = (struct sadb_ext*)pfkey_prop; - - if (pfkey_prop == NULL) { - DEBUGGING( - "pfkey_prop_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_prop, - 0, - sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)); - - pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) + - comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN; - - pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL; - pfkey_prop->sadb_prop_replay = replay; - - for (i=0; i<3; i++) { - pfkey_prop->sadb_prop_reserved[i] = 0; - } - - combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop)); - for (i = 0; i < comb_num; i++) { - memcpy (combp, &(comb[i]), sizeof(struct sadb_comb)); - combp++; - } - -#if 0 - uint8_t sadb_comb_auth; - uint8_t sadb_comb_encrypt; - uint16_t sadb_comb_flags; - uint16_t sadb_comb_auth_minbits; - uint16_t sadb_comb_auth_maxbits; - uint16_t sadb_comb_encrypt_minbits; - uint16_t sadb_comb_encrypt_maxbits; - uint32_t sadb_comb_reserved; - uint32_t sadb_comb_soft_allocations; - uint32_t sadb_comb_hard_allocations; - uint64_t sadb_comb_soft_bytes; - uint64_t sadb_comb_hard_bytes; - uint64_t sadb_comb_soft_addtime; - uint64_t sadb_comb_hard_addtime; - uint64_t sadb_comb_soft_usetime; - uint64_t sadb_comb_hard_usetime; - uint32_t sadb_comb_soft_packets; - uint32_t sadb_comb_hard_packets; -#endif -errlab: - return error; -} - -int -pfkey_supported_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - unsigned int alg_num, - struct sadb_alg* alg) -{ - int error = 0; - unsigned int i; - struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext; - struct sadb_alg *pfkey_alg; - - /* sanity checks... */ - if (pfkey_supported) { - DEBUGGING( - "pfkey_supported_build: " - "why is pfkey_supported already pointing to something?\n"); - SENDERR(EINVAL); - } - - if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) { - DEBUGGING( - "pfkey_supported_build: " - "unsupported extension type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - pfkey_supported = (struct sadb_supported*) - MALLOC(sizeof(struct sadb_supported) + - alg_num * sizeof(struct sadb_alg)); - - *pfkey_ext = (struct sadb_ext*)pfkey_supported; - - if (pfkey_supported == NULL) { - DEBUGGING( - "pfkey_supported_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_supported, - 0, - sizeof(struct sadb_supported) + - alg_num * - sizeof(struct sadb_alg)); - - pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) + - alg_num * - sizeof(struct sadb_alg)) / - IPSEC_PFKEYv2_ALIGN; - pfkey_supported->sadb_supported_exttype = exttype; - pfkey_supported->sadb_supported_reserved = 0; - - pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported)); - for(i = 0; i < alg_num; i++) { - memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg)); - pfkey_alg->sadb_alg_reserved = 0; - pfkey_alg++; - } - -#if 0 - DEBUGGING( - "pfkey_supported_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - uint8_t sadb_alg_id; - uint8_t sadb_alg_ivlen; - uint16_t sadb_alg_minbits; - uint16_t sadb_alg_maxbits; - uint16_t sadb_alg_reserved; -#endif -errlab: - return error; -} - -int -pfkey_spirange_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint32_t min, /* in network order */ - uint32_t max) /* in network order */ -{ - int error = 0; - struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext; - - /* sanity checks... */ - if (pfkey_spirange) { - DEBUGGING( - "pfkey_spirange_build: " - "why is pfkey_spirange already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (ntohl(max) < ntohl(min)) { - DEBUGGING( - "pfkey_spirange_build: " - "minspi=%08x must be < maxspi=%08x.\n", - ntohl(min), - ntohl(max)); - SENDERR(EINVAL); - } - - if (ntohl(min) <= 255) { - DEBUGGING( - "pfkey_spirange_build: " - "minspi=%08x must be > 255.\n", - ntohl(min)); - SENDERR(EEXIST); - } - - pfkey_spirange = (struct sadb_spirange*) - MALLOC(sizeof(struct sadb_spirange)); - *pfkey_ext = (struct sadb_ext*)pfkey_spirange; - - if (pfkey_spirange == NULL) { - DEBUGGING( - "pfkey_spirange_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_spirange, - 0, - sizeof(struct sadb_spirange)); - - pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN; - - pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE; - pfkey_spirange->sadb_spirange_min = min; - pfkey_spirange->sadb_spirange_max = max; - pfkey_spirange->sadb_spirange_reserved = 0; - errlab: - return error; -} - -int -pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext) -{ - int error = 0; - struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext; - - /* sanity checks... */ - if (pfkey_x_kmprivate) { - DEBUGGING( - "pfkey_x_kmprivate_build: " - "why is pfkey_x_kmprivate already pointing to something?\n"); - SENDERR(EINVAL); - } - - pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0; - - DEBUGGING( - "pfkey_x_kmprivate_build: " - "Sorry, I can't build exttype=%d yet.\n", - (*pfkey_ext)->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - - pfkey_x_kmprivate = (struct sadb_x_kmprivate*) - MALLOC(sizeof(struct sadb_x_kmprivate)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate; - - if (pfkey_x_kmprivate == NULL) { - DEBUGGING( - "pfkey_x_kmprivate_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_x_kmprivate, - 0, - sizeof(struct sadb_x_kmprivate)); - - pfkey_x_kmprivate->sadb_x_kmprivate_len = - sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN; - - pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE; - pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0; -errlab: - return error; -} - -int -pfkey_x_satype_build(struct sadb_ext** pfkey_ext, - uint8_t satype) -{ - int error = 0; - int i; - struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_satype_build:\n"); - /* sanity checks... */ - if (pfkey_x_satype) { - DEBUGGING( - "pfkey_x_satype_build: " - "why is pfkey_x_satype already pointing to something?\n"); - SENDERR(EINVAL); - } - - if (!satype) { - DEBUGGING( - "pfkey_x_satype_build: " - "SA type not set, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if (satype > SADB_SATYPE_MAX) { - DEBUGGING( - "pfkey_x_satype_build: " - "satype %d > max %d\n", - satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - pfkey_x_satype = (struct sadb_x_satype*) - MALLOC(sizeof(struct sadb_x_satype)); - - *pfkey_ext = (struct sadb_ext*)pfkey_x_satype; - - if (pfkey_x_satype == NULL) { - DEBUGGING( - "pfkey_x_satype_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - memset(pfkey_x_satype, - 0, - sizeof(struct sadb_x_satype)); - - pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN; - - pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2; - pfkey_x_satype->sadb_x_satype_satype = satype; - for (i=0; i<3; i++) { - pfkey_x_satype->sadb_x_satype_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_debug_build(struct sadb_ext** pfkey_ext, - uint32_t tunnel, - uint32_t netlink, - uint32_t xform, - uint32_t eroute, - uint32_t spi, - uint32_t radij, - uint32_t esp, - uint32_t ah, - uint32_t rcv, - uint32_t pfkey, - uint32_t ipcomp, - uint32_t verbose) -{ - int error = 0; - int i; - struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_debug_build:\n"); - /* sanity checks... */ - if (pfkey_x_debug) { - DEBUGGING( - "pfkey_x_debug_build: " - "why is pfkey_x_debug already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_debug_build: " - "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n", - tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose); - - pfkey_x_debug = (struct sadb_x_debug*) - MALLOC(sizeof(struct sadb_x_debug)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_debug; - - if (pfkey_x_debug == NULL) { - DEBUGGING( - "pfkey_x_debug_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } -#if 0 - memset(pfkey_x_debug, - 0, - sizeof(struct sadb_x_debug)); -#endif - - pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG; - - pfkey_x_debug->sadb_x_debug_tunnel = tunnel; - pfkey_x_debug->sadb_x_debug_netlink = netlink; - pfkey_x_debug->sadb_x_debug_xform = xform; - pfkey_x_debug->sadb_x_debug_eroute = eroute; - pfkey_x_debug->sadb_x_debug_spi = spi; - pfkey_x_debug->sadb_x_debug_radij = radij; - pfkey_x_debug->sadb_x_debug_esp = esp; - pfkey_x_debug->sadb_x_debug_ah = ah; - pfkey_x_debug->sadb_x_debug_rcv = rcv; - pfkey_x_debug->sadb_x_debug_pfkey = pfkey; - pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp; - pfkey_x_debug->sadb_x_debug_verbose = verbose; - - for (i=0; i<4; i++) { - pfkey_x_debug->sadb_x_debug_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext, - uint8_t type) -{ - int error = 0; - int i; - struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_nat_t_type_build:\n"); - /* sanity checks... */ - if (pfkey_x_nat_t_type) { - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "why is pfkey_x_nat_t_type already pointing to something?\n"); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "type=%d\n", type); - - pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*) - MALLOC(sizeof(struct sadb_x_nat_t_type)); - - *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type; - if (pfkey_x_nat_t_type == NULL) { - DEBUGGING( - "pfkey_x_nat_t_type_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; - pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type; - for (i=0; i<3; i++) { - pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0; - } - -errlab: - return error; -} - -int -pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext, - uint16_t exttype, - uint16_t port) -{ - int error = 0; - struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext; - - DEBUGGING( - "pfkey_x_nat_t_port_build:\n"); - /* sanity checks... */ - if (pfkey_x_nat_t_port) { - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "why is pfkey_x_nat_t_port already pointing to something?\n"); - SENDERR(EINVAL); - } - - switch (exttype) { - case SADB_X_EXT_NAT_T_SPORT: - case SADB_X_EXT_NAT_T_DPORT: - break; - default: - DEBUGGING( - "pfkey_nat_t_port_build: " - "unrecognised ext_type=%d.\n", - exttype); - SENDERR(EINVAL); - } - - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "ext=%d, port=%d\n", exttype, port); - - pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*) - MALLOC(sizeof(struct sadb_x_nat_t_port)); - *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port; - - if (pfkey_x_nat_t_port == NULL) { - DEBUGGING( - "pfkey_x_nat_t_port_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN; - pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype; - pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port; - pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0; - -errlab: - return error; -} - -int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext, - uint8_t protocol) -{ - int error = 0; - struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext; - DEBUGGING("pfkey_x_protocol_build: protocol=%u\n", protocol); - /* sanity checks... */ - if (p != 0) { - DEBUGGING("pfkey_x_protocol_build: bogus protocol pointer\n"); - SENDERR(EINVAL); - } - if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) { - DEBUGGING("pfkey_build: memory allocation failed\n"); - SENDERR(ENOMEM); - } - *pfkey_ext = (struct sadb_ext *)p; - p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t); - p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL; - p->sadb_protocol_proto = protocol; - p->sadb_protocol_flags = 0; - p->sadb_protocol_reserved2 = 0; - errlab: - return error; -} - - -#if I_DONT_THINK_THIS_WILL_BE_USEFUL -int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*) - = -{ - NULL, /* pfkey_msg_build, */ - pfkey_sa_build, - pfkey_lifetime_build, - pfkey_lifetime_build, - pfkey_lifetime_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_key_build, - pfkey_key_build, - pfkey_ident_build, - pfkey_ident_build, - pfkey_sens_build, - pfkey_prop_build, - pfkey_supported_build, - pfkey_supported_build, - pfkey_spirange_build, - pfkey_x_kmprivate_build, - pfkey_x_satype_build, - pfkey_sa_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_address_build, - pfkey_x_ext_debug_build -}; -#endif - -int -pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir) -{ - int error = 0; - unsigned ext; - unsigned total_size; - struct sadb_ext *pfkey_ext; - int extensions_seen = 0; - struct sadb_ext *extensions_check[SADB_EXT_MAX + 1]; - - if (!extensions[0]) { - DEBUGGING( - "pfkey_msg_build: " - "extensions[0] must be specified (struct sadb_msg).\n"); - SENDERR(EINVAL); - } - - total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - for (ext = 1; ext <= SADB_EXT_MAX; ext++) { - if(extensions[ext]) { - total_size += (extensions[ext])->sadb_ext_len; - } - } - - if (!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) { - DEBUGGING( - "pfkey_msg_build: " - "memory allocation failed\n"); - SENDERR(ENOMEM); - } - - DEBUGGING( - "pfkey_msg_build: " - "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n", - *pfkey_msg, - (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN), - &(extensions[0])); - memcpy(*pfkey_msg, - extensions[0], - sizeof(struct sadb_msg)); - (*pfkey_msg)->sadb_msg_len = total_size; - (*pfkey_msg)->sadb_msg_reserved = 0; - extensions_seen = 1 ; - - pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg)); - - for (ext = 1; ext <= SADB_EXT_MAX; ext++) { - /* copy from extension[ext] to buffer */ - if (extensions[ext]) { - /* Is this type of extension permitted for this type of message? */ - if (!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] & - 1<sadb_msg_type], - 1<sadb_ext_len * IPSEC_PFKEYv2_ALIGN), - ext, - extensions[ext], - pfkey_ext); - memcpy(pfkey_ext, - extensions[ext], - (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - { - char *pfkey_ext_c = (char *)pfkey_ext; - - pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN; - pfkey_ext = (struct sadb_ext *)pfkey_ext_c; - } - /* Mark that we have seen this extension and remember the header location */ - extensions_seen |= ( 1 << ext ); - } - } - - /* check required extensions */ - DEBUGGING( - "pfkey_msg_build: " - "extensions permitted=%08x, seen=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type], - extensions_seen, - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]); - - if ((extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) != - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) { - DEBUGGING( - "pfkey_msg_build: " - "required extensions missing:%08x.\n", - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] - - (extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) ); - SENDERR(EINVAL); - } - - error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir); - if (error) { - DEBUGGING( - "pfkey_msg_build: " - "Trouble parsing newly built pfkey message, error=%d.\n", - error); - SENDERR(-error); - } - -errlab: - - return error; -} diff --git a/src/libfreeswan/pfkey_v2_debug.c b/src/libfreeswan/pfkey_v2_debug.c deleted file mode 100644 index 0762d8f2b..000000000 --- a/src/libfreeswan/pfkey_v2_debug.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * @(#) pfkey version 2 debugging messages - * - * Copyright (C) 2001 Richard Guy Briggs - * and Michael Richardson - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -# include -# include - -#include "freeswan.h" -#include "pfkeyv2.h" -#include "pfkey.h" - -/* - * This file provides ASCII translations of PF_KEY magic numbers. - * - */ - -static char *pfkey_sadb_ext_strings[]={ - "reserved", /* SADB_EXT_RESERVED 0 */ - "security-association", /* SADB_EXT_SA 1 */ - "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */ - "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */ - "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */ - "source-address", /* SADB_EXT_ADDRESS_SRC 5 */ - "destination-address", /* SADB_EXT_ADDRESS_DST 6 */ - "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */ - "authentication-key", /* SADB_EXT_KEY_AUTH 8 */ - "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */ - "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */ - "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */ - "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */ - "proposal", /* SADB_EXT_PROPOSAL 13 */ - "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */ - "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */ - "spi-range", /* SADB_EXT_SPIRANGE 16 */ - "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */ - "X-satype2", /* SADB_X_EXT_SATYPE2 18 */ - "X-security-association", /* SADB_X_EXT_SA2 19 */ - "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */ - "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */ - "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */ - "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */ - "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */ - "X-set-debug", /* SADB_X_EXT_DEBUG 25 */ - "X-protocol", /* SADB_X_EXT_PROTOCOL 26 */ - "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 27 */ - "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 28 */ - "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 29 */ - "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 30 */ -}; - -const char * -pfkey_v2_sadb_ext_string(int ext) -{ - if(ext <= SADB_EXT_MAX) { - return pfkey_sadb_ext_strings[ext]; - } else { - return "unknown-ext"; - } -} - - -static char *pfkey_sadb_type_strings[]={ - "reserved", /* SADB_RESERVED */ - "getspi", /* SADB_GETSPI */ - "update", /* SADB_UPDATE */ - "add", /* SADB_ADD */ - "delete", /* SADB_DELETE */ - "get", /* SADB_GET */ - "acquire", /* SADB_ACQUIRE */ - "register", /* SADB_REGISTER */ - "expire", /* SADB_EXPIRE */ - "flush", /* SADB_FLUSH */ - "dump", /* SADB_DUMP */ - "x-promisc", /* SADB_X_PROMISC */ - "x-pchange", /* SADB_X_PCHANGE */ - "x-groupsa", /* SADB_X_GRPSA */ - "x-addflow(eroute)", /* SADB_X_ADDFLOW */ - "x-delflow(eroute)", /* SADB_X_DELFLOW */ - "x-debug", /* SADB_X_DEBUG */ - "x-nat-t-new-mapping", /* SADB_X_NAT_T_NEW_MAPPING */ -}; - -const char * -pfkey_v2_sadb_type_string(int sadb_type) -{ - if(sadb_type <= SADB_MAX) { - return pfkey_sadb_type_strings[sadb_type]; - } else { - return "unknown-sadb-type"; - } -} diff --git a/src/libfreeswan/pfkey_v2_ext_bits.c b/src/libfreeswan/pfkey_v2_ext_bits.c deleted file mode 100644 index 49b4aa567..000000000 --- a/src/libfreeswan/pfkey_v2_ext_bits.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * RFC2367 PF_KEYv2 Key management API message parser - * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parse.c. - */ - -char pfkey_v2_ext_bits_c_version[] = ""; - -# include -# include - -#include -#include -#include - -unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = { - -/* INBOUND EXTENSIONS */ -{ - -/* PERMITTED IN */ -{ -/* SADB_RESERVED */ -0 -, -/* SADB_GETSPI */ -1<. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Template from klips/net/ipsec/ipsec/ipsec_parser.c. - */ - -char pfkey_v2_parse_c_version[] = ""; - -# include -# include -# include - -# include -# include -# include /* for PRINTF_LIKE */ -# include /* for debugging and DBG_log */ - -# ifdef PLUTO -# define DEBUGGING(level, args...) { DBG_log("pfkey_lib_debug:" args); } -# else -# define DEBUGGING(level, args...) if(pfkey_lib_debug & level) { printf("pfkey_lib_debug:" args); } else { ; } -# endif - -#include -#include - - -#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0) - -static struct { - uint8_t proto; - uint8_t satype; - char* name; -} satype_tbl[] = { - { SA_ESP, SADB_SATYPE_ESP, "ESP" }, - { SA_AH, SADB_SATYPE_AH, "AH" }, - { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" }, - { SA_COMP, SADB_X_SATYPE_COMP, "COMP" }, - { SA_INT, SADB_X_SATYPE_INT, "INT" }, - { 0, 0, "UNKNOWN" } -}; - -uint8_t -satype2proto(uint8_t satype) -{ - int i =0; - - while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) { - i++; - } - return satype_tbl[i].proto; -} - -uint8_t -proto2satype(uint8_t proto) -{ - int i = 0; - - while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) { - i++; - } - return satype_tbl[i].satype; -} - -char* -satype2name(uint8_t satype) -{ - int i = 0; - - while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) { - i++; - } - return satype_tbl[i].name; -} - -char* -proto2name(uint8_t proto) -{ - int i = 0; - - while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) { - i++; - } - return satype_tbl[i].name; -} - -/* Default extension parsers taken from the KLIPS code */ - -DEBUG_NO_STATIC int -pfkey_sa_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext; -#if 0 - struct sadb_sa sav2; -#endif - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_sa_parse: entry\n"); - /* sanity checks... */ - if(!pfkey_sa) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - -#if 0 - /* check if this structure is short, and if so, fix it up. - * XXX this is NOT the way to do things. - */ - if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) { - - /* yes, so clear out a temporary structure, and copy first */ - memset(&sav2, 0, sizeof(sav2)); - memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1)); - sav2.sadb_x_sa_ref=-1; - sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN; - - pfkey_sa = &sav2; - } -#endif - - - if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n", - pfkey_sa->sadb_sa_len, - (int)sizeof(struct sadb_sa)); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n", - pfkey_sa->sadb_sa_encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n", - pfkey_sa->sadb_sa_auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "state=%d exceeds MAX=%d.\n", - pfkey_sa->sadb_sa_state, - SADB_SASTATE_MAX); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "state=%d is DEAD=%d.\n", - pfkey_sa->sadb_sa_state, - SADB_SASTATE_DEAD); - SENDERR(EINVAL); - } - - if(pfkey_sa->sadb_sa_replay > 64) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "replay window size: %d -- must be 0 <= size <= 64\n", - pfkey_sa->sadb_sa_replay); - SENDERR(EINVAL); - } - - if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) || - (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2))) - { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n", - pfkey_sa->sadb_sa_exttype, - SADB_EXT_SA, - SADB_X_EXT_SA2); - SENDERR(EINVAL); - } - - if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sa_parse: " - "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n", - pfkey_sa->sadb_x_sa_ref, - IPSEC_SAREF_NULL, - IPSEC_SA_REF_TABLE_NUM_ENTRIES); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_sa_parse: " - "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n", - pfkey_sa->sadb_sa_len, - pfkey_sa->sadb_sa_exttype, - pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype), - (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi), - pfkey_sa->sadb_sa_replay, - pfkey_sa->sadb_sa_state, - pfkey_sa->sadb_sa_auth, - pfkey_sa->sadb_sa_encrypt, - pfkey_sa->sadb_sa_flags, - pfkey_sa->sadb_x_sa_ref); - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_lifetime_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_lifetime_parse:enter\n"); - /* sanity checks... */ - if(!pfkey_lifetime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_lifetime->sadb_lifetime_len != - sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n", - pfkey_lifetime->sadb_lifetime_len, - (int)sizeof(struct sadb_lifetime)); - SENDERR(EINVAL); - } - - if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) && - (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) && - (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_lifetime_parse: " - "unexpected ext_type=%d.\n", - pfkey_lifetime->sadb_lifetime_exttype); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_lifetime_parse: " - "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n", - pfkey_lifetime->sadb_lifetime_exttype, - pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype), - pfkey_lifetime->sadb_lifetime_allocations, - (unsigned)pfkey_lifetime->sadb_lifetime_bytes, - (unsigned)pfkey_lifetime->sadb_lifetime_addtime, - (unsigned)pfkey_lifetime->sadb_lifetime_usetime, - pfkey_lifetime->sadb_x_lifetime_packets); -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_address_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int saddr_len = 0; - struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext; - struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address)); - char ipaddr_txt[ADDRTOT_BUF]; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_address_parse:enter\n"); - /* sanity checks... */ - if(!pfkey_address) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_len < - (sizeof(struct sadb_address) + sizeof(struct sockaddr))/ - IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n", - pfkey_address->sadb_address_len, - (int)sizeof(struct sadb_address), - (int)sizeof(struct sockaddr)); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "res=%d, must be zero.\n", - pfkey_address->sadb_address_reserved); - SENDERR(EINVAL); - } - - switch(pfkey_address->sadb_address_exttype) { - case SADB_EXT_ADDRESS_SRC: - case SADB_EXT_ADDRESS_DST: - case SADB_EXT_ADDRESS_PROXY: - case SADB_X_EXT_ADDRESS_DST2: - case SADB_X_EXT_ADDRESS_SRC_FLOW: - case SADB_X_EXT_ADDRESS_DST_FLOW: - case SADB_X_EXT_ADDRESS_SRC_MASK: - case SADB_X_EXT_ADDRESS_DST_MASK: - case SADB_X_EXT_NAT_T_OA: - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "unexpected ext_type=%d.\n", - pfkey_address->sadb_address_exttype); - SENDERR(EINVAL); - } - - switch(s->sa_family) { - case AF_INET: - saddr_len = sizeof(struct sockaddr_in); - sprintf(ipaddr_txt, "%d.%d.%d.%d" - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF - , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF); - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_address_parse: " - "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n", - pfkey_address->sadb_address_exttype, - pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype), - s->sa_family, - ipaddr_txt, - pfkey_address->sadb_address_proto, - ntohs(((struct sockaddr_in*)s)->sin_port)); - break; - case AF_INET6: - saddr_len = sizeof(struct sockaddr_in6); - sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x" - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[0]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[1]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[2]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[3]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[4]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[5]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[6]) - , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr[7])); - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_address_parse: " - "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n", - pfkey_address->sadb_address_exttype, - pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype), - s->sa_family, - ipaddr_txt, - pfkey_address->sadb_address_proto, - ((struct sockaddr_in6*)s)->sin6_port); - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "s->sa_family=%d not supported.\n", - s->sa_family); - SENDERR(EPFNOSUPPORT); - } - - if(pfkey_address->sadb_address_len != - DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n", - pfkey_address->sadb_address_len, - (int)sizeof(struct sadb_address), - saddr_len); - SENDERR(EINVAL); - } - - if(pfkey_address->sadb_address_prefixlen != 0) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_address_parse: " - "address prefixes not supported yet.\n"); - SENDERR(EAFNOSUPPORT); /* not supported yet */ - } - - /* XXX check if port!=0 */ - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_address_parse: successful.\n"); - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_key_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_key_parse:enter\n"); - /* sanity checks... */ - - if(!pfkey_key) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "NULL pointer passed in.\n"); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_key->sadb_key_len, - (int)sizeof(struct sadb_key)); - SENDERR(EINVAL); - } - - if(!pfkey_key->sadb_key_bits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "key length set to zero, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_len != - DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits, - PFKEYBITS)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "key length=%d does not agree with extension length=%d.\n", - pfkey_key->sadb_key_bits, - pfkey_key->sadb_key_len); - SENDERR(EINVAL); - } - - if(pfkey_key->sadb_key_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "res=%d, must be zero.\n", - pfkey_key->sadb_key_reserved); - SENDERR(EINVAL); - } - - if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) || - (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "expecting extension type AUTH or ENCRYPT, got %d.\n", - pfkey_key->sadb_key_exttype); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_key_parse: " - "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n", - pfkey_key->sadb_key_len, - pfkey_key->sadb_key_exttype, - pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype), - pfkey_key->sadb_key_bits, - pfkey_key->sadb_key_reserved); - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_ident_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_ident->sadb_ident_len, - (int)sizeof(struct sadb_ident)); - SENDERR(EINVAL); - } - - if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "ident_type=%d out of range, must be less than %d.\n", - pfkey_ident->sadb_ident_type, - SADB_IDENTTYPE_MAX); - SENDERR(EINVAL); - } - - if(pfkey_ident->sadb_ident_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "res=%d, must be zero.\n", - pfkey_ident->sadb_ident_reserved); - SENDERR(EINVAL); - } - - /* string terminator/padding must be zero */ - if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) { - if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_ident_parse: " - "string padding must be zero, last is 0x%02x.\n", - *((char*)pfkey_ident + - pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)); - SENDERR(EINVAL); - } - } - - if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) || - (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_key_parse: " - "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n", - pfkey_ident->sadb_ident_exttype); - SENDERR(EINVAL); - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_sens_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sens_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_sens->sadb_sens_len, - (int)sizeof(struct sadb_sens)); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_sens_parse: " - "Sorry, I can't parse exttype=%d yet.\n", - pfkey_ext->sadb_ext_type); -#if 0 - SENDERR(EINVAL); /* don't process these yet */ -#endif - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_prop_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i, num_comb; - struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext; - struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop)); - - /* sanity checks... */ - if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) || - (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n", - pfkey_prop->sadb_prop_len, - (int)sizeof(struct sadb_prop), - (int)sizeof(struct sadb_comb)); - SENDERR(EINVAL); - } - - if(pfkey_prop->sadb_prop_replay > 64) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "replay window size: %d -- must be 0 <= size <= 64\n", - pfkey_prop->sadb_prop_replay); - SENDERR(EINVAL); - } - - for(i=0; i<3; i++) { - if(pfkey_prop->sadb_prop_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "res[%d]=%d, must be zero.\n", - i, pfkey_prop->sadb_prop_reserved[i]); - SENDERR(EINVAL); - } - } - - num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb); - - for(i = 0; i < num_comb; i++) { - if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n", - i, - pfkey_comb->sadb_comb_auth, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_auth) { - if(!pfkey_comb->sadb_comb_auth_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(!pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_minbits, - pfkey_comb->sadb_comb_auth_maxbits); - SENDERR(EINVAL); - } - } else { - if(pfkey_comb->sadb_comb_auth_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_minbits); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_auth_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_auth_maxbits); - SENDERR(EINVAL); - } - } - - if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_comb_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n", - i, - pfkey_comb->sadb_comb_encrypt, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_encrypt) { - if(!pfkey_comb->sadb_comb_encrypt_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(!pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n", - i); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_minbits, - pfkey_comb->sadb_comb_encrypt_maxbits); - SENDERR(EINVAL); - } - } else { - if(pfkey_comb->sadb_comb_encrypt_minbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_minbits); - SENDERR(EINVAL); - } - if(pfkey_comb->sadb_comb_encrypt_maxbits) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n", - i, - pfkey_comb->sadb_comb_encrypt_maxbits); - SENDERR(EINVAL); - } - } - - /* XXX do sanity check on flags */ - - if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n", - i, - pfkey_comb->sadb_comb_soft_allocations, - pfkey_comb->sadb_comb_hard_allocations); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes, - (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime, - (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n", - i, - (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime, - (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n", - i, - pfkey_comb->sadb_x_comb_soft_packets, - pfkey_comb->sadb_x_comb_hard_packets); - SENDERR(EINVAL); - } - - if(pfkey_comb->sadb_comb_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_prop_parse: " - "comb[%d].res=%d, must be zero.\n", - i, - pfkey_comb->sadb_comb_reserved); - SENDERR(EINVAL); - } - pfkey_comb++; - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_supported_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - unsigned int i, num_alg; - struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext; - struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported)); - - /* sanity checks... */ - if((pfkey_supported->sadb_supported_len < - sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) || - (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - - sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) { - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n", - pfkey_supported->sadb_supported_len, - (int)sizeof(struct sadb_supported), - (int)sizeof(struct sadb_alg)); - SENDERR(EINVAL); - } - - if(pfkey_supported->sadb_supported_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "res=%d, must be zero.\n", - pfkey_supported->sadb_supported_reserved); - SENDERR(EINVAL); - } - - num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg); - - for(i = 0; i < num_alg; i++) { - /* process algo description */ - if(pfkey_alg->sadb_alg_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n", - i, - pfkey_alg->sadb_alg_id, - pfkey_alg->sadb_alg_ivlen, - pfkey_alg->sadb_alg_minbits, - pfkey_alg->sadb_alg_maxbits, - pfkey_alg->sadb_alg_reserved); - SENDERR(EINVAL); - } - - /* XXX can alg_id auth/enc be determined from info given? - Yes, but OpenBSD's method does not iteroperate with rfc2367. - rgb, 2000-04-06 */ - - switch(pfkey_supported->sadb_supported_exttype) { - case SADB_EXT_SUPPORTED_AUTH: - if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_AALG_MAX); - SENDERR(EINVAL); - } - break; - case SADB_EXT_SUPPORTED_ENCRYPT: - if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - break; - default: - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_supported_parse: " - "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n", - i, - pfkey_alg->sadb_alg_id, - SADB_EALG_MAX); - SENDERR(EINVAL); - } - pfkey_alg++; - } - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_spirange_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_spirange->sadb_spirange_len != - sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_spirange->sadb_spirange_len, - (int)sizeof(struct sadb_spirange)); - SENDERR(EINVAL); - } - - if(pfkey_spirange->sadb_spirange_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "reserved=%d must be set to zero.\n", - pfkey_spirange->sadb_spirange_reserved); - SENDERR(EINVAL); - } - - if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "minspi=%08x must be < maxspi=%08x.\n", - ntohl(pfkey_spirange->sadb_spirange_min), - ntohl(pfkey_spirange->sadb_spirange_max)); - SENDERR(EINVAL); - } - - if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_spirange_parse: " - "minspi=%08x must be > 255.\n", - ntohl(pfkey_spirange->sadb_spirange_min)); - SENDERR(EEXIST); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_spirange_parse: " - "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n", - pfkey_spirange->sadb_spirange_len, - pfkey_spirange->sadb_spirange_exttype, - pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype), - pfkey_spirange->sadb_spirange_min, - pfkey_spirange->sadb_spirange_max, - pfkey_spirange->sadb_spirange_reserved); - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext; - - /* sanity checks... */ - if(pfkey_x_kmprivate->sadb_x_kmprivate_len < - sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_kmprivate->sadb_x_kmprivate_len, - (int)sizeof(struct sadb_x_kmprivate)); - SENDERR(EINVAL); - } - - if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "reserved=%d must be set to zero.\n", - pfkey_x_kmprivate->sadb_x_kmprivate_reserved); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_kmprivate_parse: " - "Sorry, I can't parse exttype=%d yet.\n", - pfkey_ext->sadb_ext_type); - SENDERR(EINVAL); /* don't process these yet */ - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_satype_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i; - struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_x_satype_parse: enter\n"); - /* sanity checks... */ - if(pfkey_x_satype->sadb_x_satype_len != - sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_satype->sadb_x_satype_len, - (int)sizeof(struct sadb_x_satype)); - SENDERR(EINVAL); - } - - if(!pfkey_x_satype->sadb_x_satype_satype) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "satype is zero, must be non-zero.\n"); - SENDERR(EINVAL); - } - - if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "satype %d > max %d, invalid.\n", - pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX); - SENDERR(EINVAL); - } - - if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "proto lookup from satype=%d failed.\n", - pfkey_x_satype->sadb_x_satype_satype); - SENDERR(EINVAL); - } - - for(i = 0; i < 3; i++) { - if(pfkey_x_satype->sadb_x_satype_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_satype_parse: " - "reserved[%d]=%d must be set to zero.\n", - i, pfkey_x_satype->sadb_x_satype_reserved[i]); - SENDERR(EINVAL); - } - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_x_satype_parse: " - "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n", - pfkey_x_satype->sadb_x_satype_len, - pfkey_x_satype->sadb_x_satype_exttype, - pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype), - pfkey_x_satype->sadb_x_satype_satype, - satype2name(pfkey_x_satype->sadb_x_satype_satype), - pfkey_x_satype->sadb_x_satype_reserved[0], - pfkey_x_satype->sadb_x_satype_reserved[1], - pfkey_x_satype->sadb_x_satype_reserved[2]); -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - int i; - struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_x_debug_parse: enter\n"); - /* sanity checks... */ - if(pfkey_x_debug->sadb_x_debug_len != - sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_debug_parse: " - "size wrong ext_len=%d, key_ext_len=%d.\n", - pfkey_x_debug->sadb_x_debug_len, - (int)sizeof(struct sadb_x_debug)); - SENDERR(EINVAL); - } - - for(i = 0; i < 4; i++) { - if(pfkey_x_debug->sadb_x_debug_reserved[i]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_debug_parse: " - "reserved[%d]=%d must be set to zero.\n", - i, pfkey_x_debug->sadb_x_debug_reserved[i]); - SENDERR(EINVAL); - } - } - -errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext) -{ - int error = 0; - struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext; - - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n"); - /* sanity checks... */ - - if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n", - p->sadb_protocol_len, (int)sizeof(*p)); - SENDERR(EINVAL); - } - - if (p->sadb_protocol_reserved2 != 0) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_protocol_parse: res=%d, must be zero.\n", - p->sadb_protocol_reserved2); - SENDERR(EINVAL); - } - - errlab: - return error; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext) -{ - return 0; -} - -DEBUG_NO_STATIC int -pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext) -{ - return 0; -} - -#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME}; - -DEFINEPARSER(pfkey_sa_parse); -DEFINEPARSER(pfkey_lifetime_parse); -DEFINEPARSER(pfkey_address_parse); -DEFINEPARSER(pfkey_key_parse); -DEFINEPARSER(pfkey_ident_parse); -DEFINEPARSER(pfkey_sens_parse); -DEFINEPARSER(pfkey_prop_parse); -DEFINEPARSER(pfkey_supported_parse); -DEFINEPARSER(pfkey_spirange_parse); -DEFINEPARSER(pfkey_x_kmprivate_parse); -DEFINEPARSER(pfkey_x_satype_parse); -DEFINEPARSER(pfkey_x_ext_debug_parse); -DEFINEPARSER(pfkey_x_ext_protocol_parse); -DEFINEPARSER(pfkey_x_ext_nat_t_type_parse); -DEFINEPARSER(pfkey_x_ext_nat_t_port_parse); - -struct pf_key_ext_parsers_def *ext_default_parsers[]= -{ - NULL, /* pfkey_msg_parse, */ - &pfkey_sa_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_lifetime_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_key_parse_def, - &pfkey_key_parse_def, - &pfkey_ident_parse_def, - &pfkey_ident_parse_def, - &pfkey_sens_parse_def, - &pfkey_prop_parse_def, - &pfkey_supported_parse_def, - &pfkey_supported_parse_def, - &pfkey_spirange_parse_def, - &pfkey_x_kmprivate_parse_def, - &pfkey_x_satype_parse_def, - &pfkey_sa_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_address_parse_def, - &pfkey_x_ext_debug_parse_def, - &pfkey_x_ext_protocol_parse_def , - &pfkey_x_ext_nat_t_type_parse_def, - &pfkey_x_ext_nat_t_port_parse_def, - &pfkey_x_ext_nat_t_port_parse_def, - &pfkey_address_parse_def -}; - -int -pfkey_msg_parse(struct sadb_msg *pfkey_msg, - struct pf_key_ext_parsers_def *ext_parsers[], - struct sadb_ext *extensions[], - int dir) -{ - int error = 0; - int remain; - struct sadb_ext *pfkey_ext; - int extensions_seen = 0; - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", - pfkey_msg->sadb_msg_version, - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type), - pfkey_msg->sadb_msg_errno, - pfkey_msg->sadb_msg_satype, - satype2name(pfkey_msg->sadb_msg_satype), - pfkey_msg->sadb_msg_len, - pfkey_msg->sadb_msg_reserved, - pfkey_msg->sadb_msg_seq, - pfkey_msg->sadb_msg_pid); - - if(ext_parsers == NULL) ext_parsers = ext_default_parsers; - - pfkey_extensions_init(extensions); - - remain = pfkey_msg->sadb_msg_len; - remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; - - pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg + - sizeof(struct sadb_msg)); - - extensions[0] = (struct sadb_ext *) pfkey_msg; - - - if(pfkey_msg->sadb_msg_version != PF_KEY_V2) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "not PF_KEY_V2 msg, found %d, should be %d.\n", - pfkey_msg->sadb_msg_version, - PF_KEY_V2); - SENDERR(EINVAL); - } - - if(!pfkey_msg->sadb_msg_type) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "msg type not set, must be non-zero..\n"); - SENDERR(EINVAL); - } - - if(pfkey_msg->sadb_msg_type > SADB_MAX) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "msg type=%d > max=%d.\n", - pfkey_msg->sadb_msg_type, - SADB_MAX); - SENDERR(EINVAL); - } - - switch(pfkey_msg->sadb_msg_type) { - case SADB_GETSPI: - case SADB_UPDATE: - case SADB_ADD: - case SADB_DELETE: - case SADB_GET: - case SADB_X_GRPSA: - case SADB_X_ADDFLOW: - if(!satype2proto(pfkey_msg->sadb_msg_satype)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype %d conversion to proto failed for msg_type %d (%s).\n", - pfkey_msg->sadb_msg_satype, - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - SENDERR(EINVAL); - } else { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n", - pfkey_msg->sadb_msg_satype, - satype2name(pfkey_msg->sadb_msg_satype), - satype2proto(pfkey_msg->sadb_msg_satype), - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - } - /* fall through */ - case SADB_ACQUIRE: - case SADB_REGISTER: - case SADB_EXPIRE: - if(!pfkey_msg->sadb_msg_satype) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "satype is zero, must be non-zero for msg_type %d(%s).\n", - pfkey_msg->sadb_msg_type, - pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); - SENDERR(EINVAL); - } - default: - break; - } - - /* errno must not be set in downward messages */ - /* this is not entirely true... a response to an ACQUIRE could return an error */ - if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "errno set to %d.\n", - pfkey_msg->sadb_msg_errno); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "remain=%d, ext_type=%d(%s), ext_len=%d.\n", - remain, - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - pfkey_ext->sadb_ext_len); - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "extensions permitted=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); - - extensions_seen = 1; - - while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) { - /* Is there enough message left to support another extension header? */ - if(remain < pfkey_ext->sadb_ext_len) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "remain %d less than ext len %d.\n", - remain, pfkey_ext->sadb_ext_len); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "parsing ext type=%d(%s) remain=%d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - remain); - - /* Is the extension header type valid? */ - if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - SADB_EXT_MAX); - SENDERR(EINVAL); - } - - /* Have we already seen this type of extension? */ - if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0) - { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) already seen.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - SENDERR(EINVAL); - } - - /* Do I even know about this type of extension? */ - if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) unknown, ignoring.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - goto next_ext; - } - - /* Is this type of extension permitted for this type of message? */ - if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] & - 1<sadb_ext_type)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - 1<sadb_ext_type); - SENDERR(EINVAL); - } - - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n", - remain, - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - pfkey_ext->sadb_ext_len, - pfkey_ext, - ext_parsers[pfkey_ext->sadb_ext_type]->parser_name); - - /* Parse the extension */ - if((error = - (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "extension parsing for type %d(%s) failed with error %d.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), - error); - SENDERR(-error); - } - DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, - "pfkey_msg_parse: " - "Extension %d(%s) parsed.\n", - pfkey_ext->sadb_ext_type, - pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type)); - - /* Mark that we have seen this extension and remember the header location */ - extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type ); - extensions[pfkey_ext->sadb_ext_type] = pfkey_ext; - - next_ext: - /* Calculate how much message remains */ - remain -= pfkey_ext->sadb_ext_len; - - if(!remain) { - break; - } - /* Find the next extension header */ - pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext + - pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); - } - - if(remain) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "unexpected remainder of %d.\n", - remain); - /* why is there still something remaining? */ - SENDERR(EINVAL); - } - - /* check required extensions */ - DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, - "pfkey_msg_parse: " - "extensions permitted=%08x, seen=%08x, required=%08x.\n", - extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], - extensions_seen, - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); - - /* don't check further if it is an error return message since it - may not have a body */ - if(pfkey_msg->sadb_msg_errno) { - SENDERR(-error); - } - - if((extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) != - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "required extensions missing:%08x.\n", - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] - - (extensions_seen & - extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type])); - SENDERR(EINVAL); - } - - if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW) - && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW) - != SADB_X_EXT_ADDRESS_DELFLOW) - && (((extensions_seen & (1<sadb_sa_flags - & SADB_X_SAFLAGS_CLEARFLOW) - != SADB_X_SAFLAGS_CLEARFLOW))) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n", - SADB_X_EXT_ADDRESS_DELFLOW - - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW), - (1<sadb_msg_type) { - case SADB_ADD: - case SADB_UPDATE: - /* check maturity */ - if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != - SADB_SASTATE_MATURE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "state=%d for add or update should be MATURE=%d.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state, - SADB_SASTATE_MATURE); - SENDERR(EINVAL); - } - - /* check AH and ESP */ - switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) { - case SADB_SATYPE_AH: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth != - SADB_AALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "auth alg is zero, must be non-zero for AH SAs.\n"); - SENDERR(EINVAL); - } - if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt != - SADB_EALG_NONE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "AH handed encalg=%d, must be zero.\n", - ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt); - SENDERR(EINVAL); - } - break; - case SADB_SATYPE_ESP: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != - SADB_EALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, - ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); - SENDERR(EINVAL); - } - if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt == - SADB_EALG_NULL) && - (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth == - SADB_AALG_NONE) ) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "ESP handed encNULL+authNONE, illegal combination.\n"); - SENDERR(EINVAL); - } - break; - case SADB_X_SATYPE_COMP: - if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != - SADB_EALG_NONE)) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n", - ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, - ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); - SENDERR(EINVAL); - } - if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth != - SADB_AALG_NONE) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "COMP handed auth=%d, must be zero.\n", - ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth); - SENDERR(EINVAL); - } - break; - default: - break; - } - if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) { - DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, - "pfkey_msg_parse: " - "spi=%08x must be > 255.\n", - ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi)); - SENDERR(EINVAL); - } - default: - break; - } -errlab: - - return error; -} diff --git a/src/libfreeswan/pfkeyv2.h b/src/libfreeswan/pfkeyv2.h deleted file mode 100644 index 725997ebc..000000000 --- a/src/libfreeswan/pfkeyv2.h +++ /dev/null @@ -1,368 +0,0 @@ -/* -RFC 2367 PF_KEY Key Management API July 1998 - - -Appendix D: Sample Header File - -This file defines structures and symbols for the PF_KEY Version 2 -key management interface. It was written at the U.S. Naval Research -Laboratory. This file is in the public domain. The authors ask that -you leave this credit intact on any copies of this file. -*/ -#ifndef __PFKEY_V2_H -#define __PFKEY_V2_H 1 - -#define PF_KEY_V2 2 -#define PFKEYV2_REVISION 199806L - -#define SADB_RESERVED 0 -#define SADB_GETSPI 1 -#define SADB_UPDATE 2 -#define SADB_ADD 3 -#define SADB_DELETE 4 -#define SADB_GET 5 -#define SADB_ACQUIRE 6 -#define SADB_REGISTER 7 -#define SADB_EXPIRE 8 -#define SADB_FLUSH 9 -#define SADB_DUMP 10 -#define SADB_X_PROMISC 11 -#define SADB_X_PCHANGE 12 -#define SADB_X_GRPSA 13 -#define SADB_X_ADDFLOW 14 -#define SADB_X_DELFLOW 15 -#define SADB_X_DEBUG 16 -#define SADB_X_NAT_T_NEW_MAPPING 17 -#define SADB_MAX 17 - -struct sadb_msg { - uint8_t sadb_msg_version; - uint8_t sadb_msg_type; - uint8_t sadb_msg_errno; - uint8_t sadb_msg_satype; - uint16_t sadb_msg_len; - uint16_t sadb_msg_reserved; - uint32_t sadb_msg_seq; - uint32_t sadb_msg_pid; -}; - -struct sadb_ext { - uint16_t sadb_ext_len; - uint16_t sadb_ext_type; -}; - -struct sadb_sa { - uint16_t sadb_sa_len; - uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; - uint8_t sadb_sa_replay; - uint8_t sadb_sa_state; - uint8_t sadb_sa_auth; - uint8_t sadb_sa_encrypt; - uint32_t sadb_sa_flags; - uint32_t /*IPsecSAref_t*/ sadb_x_sa_ref; /* 32 bits */ - uint8_t sadb_x_reserved[4]; -}; - -struct sadb_sa_v1 { - uint16_t sadb_sa_len; - uint16_t sadb_sa_exttype; - uint32_t sadb_sa_spi; - uint8_t sadb_sa_replay; - uint8_t sadb_sa_state; - uint8_t sadb_sa_auth; - uint8_t sadb_sa_encrypt; - uint32_t sadb_sa_flags; -}; - -struct sadb_lifetime { - uint16_t sadb_lifetime_len; - uint16_t sadb_lifetime_exttype; - uint32_t sadb_lifetime_allocations; - uint64_t sadb_lifetime_bytes; - uint64_t sadb_lifetime_addtime; - uint64_t sadb_lifetime_usetime; - uint32_t sadb_x_lifetime_packets; - uint32_t sadb_x_lifetime_reserved; -}; - -struct sadb_address { - uint16_t sadb_address_len; - uint16_t sadb_address_exttype; - uint8_t sadb_address_proto; - uint8_t sadb_address_prefixlen; - uint16_t sadb_address_reserved; -}; - -struct sadb_key { - uint16_t sadb_key_len; - uint16_t sadb_key_exttype; - uint16_t sadb_key_bits; - uint16_t sadb_key_reserved; -}; - -struct sadb_ident { - uint16_t sadb_ident_len; - uint16_t sadb_ident_exttype; - uint16_t sadb_ident_type; - uint16_t sadb_ident_reserved; - uint64_t sadb_ident_id; -}; - -struct sadb_sens { - uint16_t sadb_sens_len; - uint16_t sadb_sens_exttype; - uint32_t sadb_sens_dpd; - uint8_t sadb_sens_sens_level; - uint8_t sadb_sens_sens_len; - uint8_t sadb_sens_integ_level; - uint8_t sadb_sens_integ_len; - uint32_t sadb_sens_reserved; -}; - -struct sadb_prop { - uint16_t sadb_prop_len; - uint16_t sadb_prop_exttype; - uint8_t sadb_prop_replay; - uint8_t sadb_prop_reserved[3]; -}; - -struct sadb_comb { - uint8_t sadb_comb_auth; - uint8_t sadb_comb_encrypt; - uint16_t sadb_comb_flags; - uint16_t sadb_comb_auth_minbits; - uint16_t sadb_comb_auth_maxbits; - uint16_t sadb_comb_encrypt_minbits; - uint16_t sadb_comb_encrypt_maxbits; - uint32_t sadb_comb_reserved; - uint32_t sadb_comb_soft_allocations; - uint32_t sadb_comb_hard_allocations; - uint64_t sadb_comb_soft_bytes; - uint64_t sadb_comb_hard_bytes; - uint64_t sadb_comb_soft_addtime; - uint64_t sadb_comb_hard_addtime; - uint64_t sadb_comb_soft_usetime; - uint64_t sadb_comb_hard_usetime; - uint32_t sadb_x_comb_soft_packets; - uint32_t sadb_x_comb_hard_packets; -}; - -struct sadb_supported { - uint16_t sadb_supported_len; - uint16_t sadb_supported_exttype; - uint32_t sadb_supported_reserved; -}; - -struct sadb_alg { - uint8_t sadb_alg_id; - uint8_t sadb_alg_ivlen; - uint16_t sadb_alg_minbits; - uint16_t sadb_alg_maxbits; - uint16_t sadb_alg_reserved; -}; - -struct sadb_spirange { - uint16_t sadb_spirange_len; - uint16_t sadb_spirange_exttype; - uint32_t sadb_spirange_min; - uint32_t sadb_spirange_max; - uint32_t sadb_spirange_reserved; -}; - -struct sadb_x_kmprivate { - uint16_t sadb_x_kmprivate_len; - uint16_t sadb_x_kmprivate_exttype; - uint32_t sadb_x_kmprivate_reserved; -}; - -struct sadb_x_satype { - uint16_t sadb_x_satype_len; - uint16_t sadb_x_satype_exttype; - uint8_t sadb_x_satype_satype; - uint8_t sadb_x_satype_reserved[3]; -}; - -struct sadb_x_policy { - uint16_t sadb_x_policy_len; - uint16_t sadb_x_policy_exttype; - uint16_t sadb_x_policy_type; - uint8_t sadb_x_policy_dir; - uint8_t sadb_x_policy_reserved; - uint32_t sadb_x_policy_id; - uint32_t sadb_x_policy_reserved2; -}; - -struct sadb_x_debug { - uint16_t sadb_x_debug_len; - uint16_t sadb_x_debug_exttype; - uint32_t sadb_x_debug_tunnel; - uint32_t sadb_x_debug_netlink; - uint32_t sadb_x_debug_xform; - uint32_t sadb_x_debug_eroute; - uint32_t sadb_x_debug_spi; - uint32_t sadb_x_debug_radij; - uint32_t sadb_x_debug_esp; - uint32_t sadb_x_debug_ah; - uint32_t sadb_x_debug_rcv; - uint32_t sadb_x_debug_pfkey; - uint32_t sadb_x_debug_ipcomp; - uint32_t sadb_x_debug_verbose; - uint8_t sadb_x_debug_reserved[4]; -}; - -struct sadb_x_nat_t_type { - uint16_t sadb_x_nat_t_type_len; - uint16_t sadb_x_nat_t_type_exttype; - uint8_t sadb_x_nat_t_type_type; - uint8_t sadb_x_nat_t_type_reserved[3]; -}; -struct sadb_x_nat_t_port { - uint16_t sadb_x_nat_t_port_len; - uint16_t sadb_x_nat_t_port_exttype; - uint16_t sadb_x_nat_t_port_port; - uint16_t sadb_x_nat_t_port_reserved; -}; - -/* - * A protocol structure for passing through the transport level - * protocol. It contains more fields than are actually used/needed - * but it is this way to be compatible with the structure used in - * OpenBSD (http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/pfkeyv2.h) - */ -struct sadb_protocol { - uint16_t sadb_protocol_len; - uint16_t sadb_protocol_exttype; - uint8_t sadb_protocol_proto; - uint8_t sadb_protocol_direction; - uint8_t sadb_protocol_flags; - uint8_t sadb_protocol_reserved2; -}; - -#define SADB_EXT_RESERVED 0 -#define SADB_EXT_SA 1 -#define SADB_EXT_LIFETIME_CURRENT 2 -#define SADB_EXT_LIFETIME_HARD 3 -#define SADB_EXT_LIFETIME_SOFT 4 -#define SADB_EXT_ADDRESS_SRC 5 -#define SADB_EXT_ADDRESS_DST 6 -#define SADB_EXT_ADDRESS_PROXY 7 -#define SADB_EXT_KEY_AUTH 8 -#define SADB_EXT_KEY_ENCRYPT 9 -#define SADB_EXT_IDENTITY_SRC 10 -#define SADB_EXT_IDENTITY_DST 11 -#define SADB_EXT_SENSITIVITY 12 -#define SADB_EXT_PROPOSAL 13 -#define SADB_EXT_SUPPORTED_AUTH 14 -#define SADB_EXT_SUPPORTED_ENCRYPT 15 -#define SADB_EXT_SPIRANGE 16 -#define SADB_X_EXT_KMPRIVATE 17 -#define SADB_X_EXT_SATYPE2 18 -#ifdef KERNEL26_HAS_KAME_DUPLICATES -#define SADB_X_EXT_POLICY 18 -#endif -#define SADB_X_EXT_SA2 19 -#define SADB_X_EXT_ADDRESS_DST2 20 -#define SADB_X_EXT_ADDRESS_SRC_FLOW 21 -#define SADB_X_EXT_ADDRESS_DST_FLOW 22 -#define SADB_X_EXT_ADDRESS_SRC_MASK 23 -#define SADB_X_EXT_ADDRESS_DST_MASK 24 -#define SADB_X_EXT_DEBUG 25 -#define SADB_X_EXT_PROTOCOL 26 -#define SADB_X_EXT_NAT_T_TYPE 27 -#define SADB_X_EXT_NAT_T_SPORT 28 -#define SADB_X_EXT_NAT_T_DPORT 29 -#define SADB_X_EXT_NAT_T_OA 30 -#define SADB_EXT_MAX 30 - -/* SADB_X_DELFLOW required over and above SADB_X_SAFLAGS_CLEARFLOW */ -#define SADB_X_EXT_ADDRESS_DELFLOW \ - ( (1<" -.sp -.B "int portof(const ip_address *src);" -.br -.B "void setportof(int port, ip_address *dst);" -.br -.B "struct sockaddr *sockaddrof(ip_address *src);" -.br -.B "size_t sockaddrlenof(const ip_address *src);" -.SH DESCRIPTION -The -.B -internal type -.I ip_address -contains one of the -.I sockaddr -types internally. -\fIReliance on this feature is discouraged\fR, -but it may occasionally be necessary. -These functions provide low-level tools for this purpose. -.PP -.I Portof -and -.I setportof -respectively read and write the port-number field of the internal -.IR sockaddr . -The values are in network byte order. -.PP -.I Sockaddrof -returns a pointer to the internal -.IR sockaddr , -for passing to other functions. -.PP -.I Sockaddrlenof -reports the size of the internal -.IR sockaddr , -for use in storage allocation. -.SH SEE ALSO -inet(3), ipsec_initaddr(3) -.SH DIAGNOSTICS -.I Portof -returns -.BR \-1 , -.I sockaddrof -returns -.BR NULL , -and -.I sockaddrlenof -returns -.B 0 -if an unknown address family is found within the -.IR ip_address . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -These functions all depend on low-level details of the -.I ip_address -type, which are in principle subject to change. -Avoid using them unless really necessary. diff --git a/src/libfreeswan/portof.c b/src/libfreeswan/portof.c deleted file mode 100644 index c44b839f3..000000000 --- a/src/libfreeswan/portof.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * low-level ip_address ugliness - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - - portof - get the port field of an ip_address - */ -int /* network order */ -portof(src) -const ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return src->u.v4.sin_port; - break; - case AF_INET6: - return src->u.v6.sin6_port; - break; - default: - return -1; /* "can't happen" */ - break; - } -} - -/* - - setportof - set the port field of an ip_address - */ -void -setportof(port, dst) -int port; /* network order */ -ip_address *dst; -{ - switch (dst->u.v4.sin_family) { - case AF_INET: - dst->u.v4.sin_port = port; - break; - case AF_INET6: - dst->u.v6.sin6_port = port; - break; - } -} - -/* - - sockaddrof - get a pointer to the sockaddr hiding inside an ip_address - */ -struct sockaddr * -sockaddrof(src) -ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return (struct sockaddr *)&src->u.v4; - break; - case AF_INET6: - return (struct sockaddr *)&src->u.v6; - break; - default: - return NULL; /* "can't happen" */ - break; - } -} - -/* - - sockaddrlenof - get length of the sockaddr hiding inside an ip_address - */ -size_t /* 0 for error */ -sockaddrlenof(src) -const ip_address *src; -{ - switch (src->u.v4.sin_family) { - case AF_INET: - return sizeof(src->u.v4); - break; - case AF_INET6: - return sizeof(src->u.v6); - break; - default: - return 0; - break; - } -} diff --git a/src/libfreeswan/rangetoa.c b/src/libfreeswan/rangetoa.c deleted file mode 100644 index 704558248..000000000 --- a/src/libfreeswan/rangetoa.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * convert binary form of address range to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - rangetoa - convert address range to ASCII - */ -size_t /* space needed for full conversion */ -rangetoa(addrs, format, dst, dstlen) -struct in_addr addrs[2]; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - int n; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtoa(addrs[0], 0, dst, dstlen); - if (len < dstlen) - for (p = dst + len - 1, n = 3; len < dstlen && n > 0; - p++, len++, n--) - *p = '.'; - else - p = NULL; - if (len < dstlen) - rest = dstlen - len; - else { - if (dstlen > 0) - *(dst + dstlen - 1) = '\0'; - rest = 0; - } - - len += addrtoa(addrs[1], 0, p, rest); - - return len; -} diff --git a/src/libfreeswan/rangetosubnet.3 b/src/libfreeswan/rangetosubnet.3 deleted file mode 100644 index 100b42bd9..000000000 --- a/src/libfreeswan/rangetosubnet.3 +++ /dev/null @@ -1,58 +0,0 @@ -.TH IPSEC_RANGETOSUBNET 3 "8 Sept 2000" -.SH NAME -ipsec rangetosubnet \- convert address range to subnet -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *rangetosubnet(const ip_address *start," -.ti +1c -.B "const ip_address *stop, ip_subnet *dst);" -.SH DESCRIPTION -.I Rangetosubnet -accepts two IP addresses which define an address range, -from -.I start -to -.I stop -inclusive, -and converts this to a subnet if possible. -The addresses must both be IPv4 or both be IPv6, -and the address family of the resulting subnet is the same. -.PP -.I Rangetosubnet -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.SH SEE ALSO -ipsec_initsubnet(3), ipsec_ttosubnet(3) -.SH DIAGNOSTICS -Fatal errors in -.I rangetosubnet -are: -mixed address families; -unknown address family; -.I start -and -.I stop -do not define a subnet. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = rangetosubnet( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/rangetosubnet.c b/src/libfreeswan/rangetosubnet.c deleted file mode 100644 index 2a989300e..000000000 --- a/src/libfreeswan/rangetosubnet.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * express an address range as a subnet (if possible) - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - rangetosubnet - turn an address range into a subnet, if possible - * - * A range which is a valid subnet will have a network part which is the - * same in the from value and the to value, followed by a host part which - * is all 0 in the from value and all 1 in the to value. - */ -err_t -rangetosubnet(from, to, dst) -const ip_address *from; -const ip_address *to; -ip_subnet *dst; -{ - unsigned const char *fp; - unsigned const char *tp; - unsigned fb; - unsigned tb; - unsigned const char *f; - unsigned const char *t; - size_t n; - size_t n2; - int i; - int nnet; - unsigned m; - - if (addrtypeof(from) != addrtypeof(to)) - return "mismatched address types"; - n = addrbytesptr(from, &fp); - if (n == 0) - return "unknown address type"; - n2 = addrbytesptr(to, &tp); - if (n != n2) - return "internal size mismatch in rangetosubnet"; - - f = fp; - t = tp; - nnet = 0; - for (i = n; i > 0 && *f == *t; i--, f++, t++) - nnet += 8; - if (i > 0 && !(*f == 0x00 && *t == 0xff)) { /* mid-byte bdry. */ - fb = *f++; - tb = *t++; - i--; - m = 0x80; - while ((fb&m) == (tb&m)) { - fb &= ~m; - tb |= m; - m >>= 1; - nnet++; - } - if (fb != 0x00 || tb != 0xff) - return "not a valid subnet"; - } - for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++) - continue; - - if (i != 0) - return "invalid subnet"; - - return initsubnet(from, nnet, 'x', dst); -} - - - -#ifdef RANGETOSUBNET_MAIN - -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - ip_address start; - ip_address stop; - ip_subnet sub; - char buf[100]; - const char *oops; - size_t n; - int af; - int i; - - if (argc == 2 && strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - if (argc < 3) { - fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]); - fprintf(stderr, " or: %s -r\n", argv[0]); - exit(2); - } - - af = AF_INET; - i = 1; - if (strcmp(argv[i], "-6") == 0) { - af = AF_INET6; - i++; - } - - oops = ttoaddr(argv[i], 0, af, &start); - if (oops != NULL) { - fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops); - exit(1); - } - oops = ttoaddr(argv[i+1], 0, af, &stop); - if (oops != NULL) { - fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops); - exit(1); - } - oops = rangetosubnet(&start, &stop, &sub); - if (oops != NULL) { - fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettot(&sub, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion", argv[0]); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int family; - char *start; - char *stop; - char *output; /* NULL means error expected */ -} rtab[] = { - {4, "1.2.3.0", "1.2.3.255", "1.2.3.0/24"}, - {4, "1.2.3.0", "1.2.3.7", "1.2.3.0/29"}, - {4, "1.2.3.240", "1.2.3.255", "1.2.3.240/28"}, - {4, "0.0.0.0", "255.255.255.255", "0.0.0.0/0"}, - {4, "1.2.3.4", "1.2.3.4", "1.2.3.4/32"}, - {4, "1.2.3.0", "1.2.3.254", NULL}, - {4, "1.2.3.0", "1.2.3.126", NULL}, - {4, "1.2.3.0", "1.2.3.125", NULL}, - {4, "1.2.0.0", "1.2.255.255", "1.2.0.0/16"}, - {4, "1.2.0.0", "1.2.0.255", "1.2.0.0/24"}, - {4, "1.2.255.0", "1.2.255.255", "1.2.255.0/24"}, - {4, "1.2.255.0", "1.2.254.255", NULL}, - {4, "1.2.255.1", "1.2.255.255", NULL}, - {4, "1.2.0.1", "1.2.255.255", NULL}, - {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:ffff", "1:2:3:4:5:6:7:0/112"}, - {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:fff", "1:2:3:4:5:6:7:0/116"}, - {6, "1:2:3:4:5:6:7:f0", "1:2:3:4:5:6:7:ff", "1:2:3:4:5:6:7:f0/124"}, - {4, NULL, NULL, NULL}, -}; - -void -regress() -{ - struct rtab *r; - int status = 0; - ip_address start; - ip_address stop; - ip_subnet sub; - char buf[100]; - const char *oops; - size_t n; - int af; - - for (r = rtab; r->start != NULL; r++) { - af = (r->family == 4) ? AF_INET : AF_INET6; - oops = ttoaddr(r->start, 0, af, &start); - if (oops != NULL) { - printf("surprise failure converting `%s'\n", r->start); - exit(1); - } - oops = ttoaddr(r->stop, 0, af, &stop); - if (oops != NULL) { - printf("surprise failure converting `%s'\n", r->stop); - exit(1); - } - oops = rangetosubnet(&start, &stop, &sub); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s'-`%s' rangetosubnet failed: %s\n", - r->start, r->stop, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n", - r->start, r->stop); - status = 1; - } else { - n = subnettot(&sub, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s'-`%s' subnettot failed: need %ld\n", - r->start, r->stop, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s'-`%s' gave `%s', expected `%s'\n", - r->start, r->stop, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* RANGETOSUBNET_MAIN */ diff --git a/src/libfreeswan/sameaddr.3 b/src/libfreeswan/sameaddr.3 deleted file mode 100644 index 62886bf1a..000000000 --- a/src/libfreeswan/sameaddr.3 +++ /dev/null @@ -1,164 +0,0 @@ -.TH IPSEC_ANYADDR 3 "28 Nov 2000" -.SH NAME -ipsec sameaddr \- are two addresses the same? -.br -ipsec addrcmp \- ordered comparison of addresses -.br -ipsec samesubnet \- are two subnets the same? -.br -ipsec addrinsubnet \- is an address within a subnet? -.br -ipsec subnetinsubnet \- is a subnet within another subnet? -.br -ipsec subnetishost \- is a subnet a single host? -.br -ipsec samesaid \- are two SA IDs the same? -.br -ipsec sameaddrtype \- are two addresses of the same address family? -.br -ipsec samesubnettype \- are two subnets of the same address family? -.SH SYNOPSIS -.B "#include -.sp -.B "int sameaddr(const ip_address *a, const ip_address *b);" -.br -.B "int addrcmp(const ip_address *a, const ip_address *b);" -.br -.B "int samesubnet(const ip_subnet *a, const ip_subnet *b);" -.br -.B "int addrinsubnet(const ip_address *a, const ip_subnet *s);" -.br -.B "int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);" -.br -.B "int subnetishost(const ip_subnet *s);" -.br -.B "int samesaid(const ip_said *a, const ip_said *b);" -.br -.B "int sameaddrtype(const ip_address *a, const ip_address *b);" -.br -.B "int samesubnettype(const ip_subnet *a, const ip_subnet *b);" -.SH DESCRIPTION -These functions do various comparisons and tests on the -.I ip_address -type and -.I ip_subnet -types. -.PP -.I Sameaddr -returns -non-zero -if addresses -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -Addresses of different families are never identical. -.PP -.I Addrcmp -returns -.BR \-1 , -.BR 0 , -or -.BR 1 -respectively -if address -.I a -is less than, equal to, or greater than -.IR b . -If they are not of the same address family, -they are never equal; -the ordering reported in this case is arbitrary -(and probably not useful) but consistent. -.PP -.I Samesubnet -returns -non-zero -if subnets -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -Subnets of different address families are never identical. -.PP -.I Addrinsubnet -returns -non-zero -if address -.I a -is within subnet -.IR s -and -.B 0 -otherwise. -An address is never within a -subnet of a different address family. -.PP -.I Subnetinsubnet -returns -non-zero -if subnet -.I a -is a subset of subnet -.IR b -and -.B 0 -otherwise. -A subnet is deemed to be a subset of itself. -A subnet is never a subset of another -subnet if their address families differ. -.PP -.I Subnetishost -returns -non-zero -if subnet -.I s -is in fact only a single host, -and -.B 0 -otherwise. -.PP -.I Samesaid -returns -non-zero -if SA IDs -.I a -and -.IR b -are identical, -and -.B 0 -otherwise. -.PP -.I Sameaddrtype -returns -non-zero -if addresses -.I a -and -.IR b -are of the same address family, -and -.B 0 -otherwise. -.PP -.I Samesubnettype -returns -non-zero -if subnets -.I a -and -.IR b -are of the same address family, -and -.B 0 -otherwise. -.SH SEE ALSO -inet(3), ipsec_initaddr(3) -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. diff --git a/src/libfreeswan/sameaddr.c b/src/libfreeswan/sameaddr.c deleted file mode 100644 index 47daaa4ee..000000000 --- a/src/libfreeswan/sameaddr.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * comparisons - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -static int samenbits(const ip_address *a, const ip_address *b, int n); - -/* - - addrcmp - compare two addresses - * Caution, the order of the tests is subtle: doing type test before - * size test can yield cases where ac. - */ -int /* like memcmp */ -addrcmp(a, b) -const ip_address *a; -const ip_address *b; -{ - int at = addrtypeof(a); - int bt = addrtypeof(b); - const unsigned char *ap; - const unsigned char *bp; - size_t as = addrbytesptr(a, &ap); - size_t bs = addrbytesptr(b, &bp); - size_t n = (as < bs) ? as : bs; /* min(as, bs) */ - int c = memcmp(ap, bp, n); - - if (c != 0) /* bytes differ */ - return (c < 0) ? -1 : 1; - if (as != bs) /* comparison incomplete: lexical order */ - return (as < bs) ? -1 : 1; - if (at != bt) /* bytes same but not same type: break tie */ - return (at < bt) ? -1 : 1; - return 0; -} - -/* - - sameaddr - are two addresses the same? - */ -int -sameaddr(a, b) -const ip_address *a; -const ip_address *b; -{ - return (addrcmp(a, b) == 0) ? 1 : 0; -} - -/* - - samesubnet - are two subnets the same? - */ -int -samesubnet(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - if (!sameaddr(&a->addr, &b->addr)) /* also does type check */ - return 0; - if (a->maskbits != b->maskbits) - return 0; - return 1; -} - -/* - - subnetishost - is a subnet in fact a single host? - */ -int -subnetishost(a) -const ip_subnet *a; -{ - return (a->maskbits == addrlenof(&a->addr)*8) ? 1 : 0; -} - -/* - - samesaid - are two SA IDs the same? - */ -int -samesaid(a, b) -const ip_said *a; -const ip_said *b; -{ - if (a->spi != b->spi) /* test first, most likely to be different */ - return 0; - if (!sameaddr(&a->dst, &b->dst)) - return 0; - if (a->proto != b->proto) - return 0; - return 1; -} - -/* - - sameaddrtype - do two addresses have the same type? - */ -int -sameaddrtype(a, b) -const ip_address *a; -const ip_address *b; -{ - return (addrtypeof(a) == addrtypeof(b)) ? 1 : 0; -} - -/* - - samesubnettype - do two subnets have the same type? - */ -int -samesubnettype(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - return (subnettypeof(a) == subnettypeof(b)) ? 1 : 0; -} - -/* - - addrinsubnet - is this address in this subnet? - */ -int -addrinsubnet(a, s) -const ip_address *a; -const ip_subnet *s; -{ - if (addrtypeof(a) != subnettypeof(s)) - return 0; - if (!samenbits(a, &s->addr, s->maskbits)) - return 0; - return 1; -} - -/* - - subnetinsubnet - is one subnet within another? - */ -int -subnetinsubnet(a, b) -const ip_subnet *a; -const ip_subnet *b; -{ - if (subnettypeof(a) != subnettypeof(b)) - return 0; - if (a->maskbits < b->maskbits) /* a is bigger than b */ - return 0; - if (!samenbits(&a->addr, &b->addr, b->maskbits)) - return 0; - return 1; -} - -/* - - samenbits - do two addresses have the same first n bits? - */ -static int -samenbits(a, b, nbits) -const ip_address *a; -const ip_address *b; -int nbits; -{ - const unsigned char *ap; - const unsigned char *bp; - size_t n; - int m; - - if (addrtypeof(a) != addrtypeof(b)) - return 0; /* arbitrary */ - n = addrbytesptr(a, &ap); - if (n == 0) - return 0; /* arbitrary */ - (void) addrbytesptr(b, &bp); - if (nbits > n*8) - return 0; /* "can't happen" */ - - for (; nbits >= 8 && *ap == *bp; nbits -= 8, ap++, bp++) - continue; - if (nbits >= 8) - return 0; - if (nbits > 0) { /* partial byte */ - m = ~(0xff >> nbits); - if ((*ap & m) != (*bp & m)) - return 0; - } - return 1; -} diff --git a/src/libfreeswan/satot.c b/src/libfreeswan/satot.c deleted file mode 100644 index a3feb1591..000000000 --- a/src/libfreeswan/satot.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * convert from binary form of SA ID to text - * Copyright (C) 2000, 2001 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -static struct typename { - char type; - char *name; -} typenames[] = { - { SA_AH, "ah" }, - { SA_ESP, "esp" }, - { SA_IPIP, "tun" }, - { SA_COMP, "comp" }, - { SA_INT, "int" }, - { 0, NULL } -}; - -/* - - satot - convert SA to text "ah507@1.2.3.4" - */ -size_t /* space needed for full conversion */ -satot(sa, format, dst, dstlen) -const ip_said *sa; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len = 0; /* 0 means "not recognized yet" */ - int base; - int showversion; /* use delimiter to show IP version? */ - struct typename *tn; - char *p; - char *pre; - char buf[10+1+ULTOT_BUF+ADDRTOT_BUF]; - char unk[10]; - - switch (format) { - case 0: - base = 16; - showversion = 1; - break; - case 'f': - base = 17; - showversion = 1; - break; - case 'x': - base = 'x'; - showversion = 0; - break; - case 'd': - base = 10; - showversion = 0; - break; - default: - return 0; - break; - } - - pre = NULL; - for (tn = typenames; tn->name != NULL; tn++) - if (sa->proto == tn->type) { - pre = tn->name; - break; /* NOTE BREAK OUT */ - } - if (pre == NULL) { /* unknown protocol */ - strncpy(unk, "unk", sizeof(unk)); - (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk), - sizeof(unk)-strlen(unk)); - pre = unk; - } - - if (strcmp(pre, PASSTHROUGHTYPE) == 0 && - sa->spi == PASSTHROUGHSPI && - isunspecaddr(&sa->dst)) { - strncpy(buf, (addrtypeof(&sa->dst) == AF_INET) ? - PASSTHROUGH4NAME : - PASSTHROUGH6NAME, sizeof(buf)); - len = strlen(buf); - } - - if (sa->proto == SA_INT && addrtypeof(&sa->dst) == AF_INET && - isunspecaddr(&sa->dst)) { - switch (ntohl(sa->spi)) { - case SPI_PASS: p = "%pass"; break; - case SPI_DROP: p = "%drop"; break; - case SPI_REJECT: p = "%reject"; break; - case SPI_HOLD: p = "%hold"; break; - case SPI_TRAP: p = "%trap"; break; - case SPI_TRAPSUBNET: p = "%trapsubnet"; break; - default: p = NULL; break; - } - if (p != NULL) { - strncpy(buf, p, sizeof(buf)); - len = strlen(buf); - } - } - - if (len == 0) { /* general case needed */ - strncpy(buf, pre, sizeof(buf)); - len = strlen(buf); - if (showversion) { - *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' : - ':'; - len++; - *(buf+len) = '\0'; - } - len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len); - *(buf+len-1) = '@'; - len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len); - } - - if (dst != NULL) { - if (len > dstlen) - *(buf+dstlen-1) = '\0'; - strncpy(dst, buf, dstlen); - } - return len; -} diff --git a/src/libfreeswan/subnetof.3 b/src/libfreeswan/subnetof.3 deleted file mode 100644 index aacc76d2c..000000000 --- a/src/libfreeswan/subnetof.3 +++ /dev/null @@ -1,46 +0,0 @@ -.TH IPSEC_SUBNETOF 3 "11 June 2001" -.SH NAME -ipsec subnetof \- given Internet address and subnet mask, return subnet number -.br -ipsec hostof \- given Internet address and subnet mask, return host part -.br -ipsec broadcastof \- given Internet address and subnet mask, return broadcast address -.SH SYNOPSIS -.B "#include -.sp -.B "struct in_addr subnetof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.br -.B "struct in_addr hostof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.br -.B "struct in_addr broadcastof(struct in_addr addr," -.ti +1c -.B "struct in_addr mask);" -.SH DESCRIPTION -These functions are obsolete; see -.IR ipsec_networkof (3) -for their replacements. -.PP -.I Subnetof -takes an Internet -.I address -and a subnet -.I mask -and returns the network part of the address -(all in network byte order). -.I Hostof -similarly returns the host part, and -.I broadcastof -returns the broadcast address (all-1s convention) for the network. -.PP -These functions are provided to hide the Internet bit-munging inside -an API, in hopes of easing the eventual transition to IPv6. -.SH SEE ALSO -inet(3), ipsec_atosubnet(3) -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -Calling functions for this is more costly than doing it yourself. diff --git a/src/libfreeswan/subnetof.c b/src/libfreeswan/subnetof.c deleted file mode 100644 index ec9b8ec7d..000000000 --- a/src/libfreeswan/subnetof.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * minor network-address manipulation utilities - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnetof - given address and mask, return subnet part - */ -struct in_addr -subnetof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr & mask.s_addr; - return result; -} - -/* - - hostof - given address and mask, return host part - */ -struct in_addr -hostof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr & ~mask.s_addr; - return result; -} - -/* - - broadcastof - given (network) address and mask, return broadcast address - */ -struct in_addr -broadcastof(addr, mask) -struct in_addr addr; -struct in_addr mask; -{ - struct in_addr result; - - result.s_addr = addr.s_addr | ~mask.s_addr; - return result; -} diff --git a/src/libfreeswan/subnettoa.c b/src/libfreeswan/subnettoa.c deleted file mode 100644 index 694fa40da..000000000 --- a/src/libfreeswan/subnettoa.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * convert binary form of subnet description to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettoa - convert address and mask to ASCII "addr/mask" - * Output expresses the mask as a bit count if possible, else dotted decimal. - */ -size_t /* space needed for full conversion */ -subnettoa(addr, mask, format, dst, dstlen) -struct in_addr addr; -struct in_addr mask; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - int n; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtoa(addr, 0, dst, dstlen); - if (len < dstlen) { - dst[len - 1] = '/'; - p = dst + len; - rest = dstlen - len; - } else { - p = NULL; - rest = 0; - } - - n = masktobits(mask); - if (n >= 0) - len += ultoa((unsigned long)n, 10, p, rest); - else - len += addrtoa(mask, 0, p, rest); - - return len; -} diff --git a/src/libfreeswan/subnettot.c b/src/libfreeswan/subnettot.c deleted file mode 100644 index 64d511ba2..000000000 --- a/src/libfreeswan/subnettot.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * convert binary form of subnet description to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettot - convert subnet to text "addr/bitcount" - */ -size_t /* space needed for full conversion */ -subnettot(sub, format, dst, dstlen) -const ip_subnet *sub; -int format; /* character */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - size_t len; - size_t rest; - char *p; - - switch (format) { - case 0: - break; - default: - return 0; - break; - } - - len = addrtot(&sub->addr, format, dst, dstlen); - if (len < dstlen) { - dst[len - 1] = '/'; - p = dst + len; - rest = dstlen - len; - } else { - p = NULL; - rest = 0; - } - - - len += ultoa((unsigned long)sub->maskbits, 10, p, rest); - - return len; -} diff --git a/src/libfreeswan/subnettypeof.c b/src/libfreeswan/subnettypeof.c deleted file mode 100644 index 96c283c04..000000000 --- a/src/libfreeswan/subnettypeof.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * extract parts of an ip_subnet, and related - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - subnettypeof - get the address type of an ip_subnet - */ -int -subnettypeof(src) -const ip_subnet *src; -{ - return src->addr.u.v4.sin_family; -} - -/* - - networkof - get the network address of a subnet - */ -void -networkof(src, dst) -const ip_subnet *src; -ip_address *dst; -{ - *dst = src->addr; -} - -/* - - maskof - get the mask of a subnet, as an address - */ -void -maskof(src, dst) -const ip_subnet *src; -ip_address *dst; -{ - int b; - unsigned char buf[16]; - size_t n = addrlenof(&src->addr); - unsigned char *p; - - if (src->maskbits > n*8 || n > sizeof(buf)) - return; /* "can't happen" */ - - p = buf; - for (b = src->maskbits; b >= 8; b -= 8) - *p++ = 0xff; - if (b != 0) - *p++ = (0xff << (8 - b)) & 0xff; - while (p - buf < n) - *p++ = 0; - - (void) initaddr(buf, n, addrtypeof(&src->addr), dst); -} - -/* - - masktocount - convert a mask, expressed as an address, to a bit count - */ -int /* -1 if not valid mask */ -masktocount(src) -const ip_address *src; -{ - int b; - unsigned const char *bp; - size_t n; - unsigned const char *p; - unsigned const char *stop; - - n = addrbytesptr(src, &bp); - if (n == 0) - return -1; - - p = bp; - stop = bp + n; - - n = 0; - while (p < stop && *p == 0xff) { - p++; - n += 8; - } - if (p < stop && *p != 0) { /* boundary in mid-byte */ - b = *p++; - while (b&0x80) { - b <<= 1; - n++; - } - if ((b&0xff) != 0) - return -1; /* bits not contiguous */ - } - while (p < stop && *p == 0) - p++; - - if (p != stop) - return -1; - - return n; -} diff --git a/src/libfreeswan/ttoaddr.3 b/src/libfreeswan/ttoaddr.3 deleted file mode 100644 index d43d2b16f..000000000 --- a/src/libfreeswan/ttoaddr.3 +++ /dev/null @@ -1,374 +0,0 @@ -.TH IPSEC_TTOADDR 3 "28 Sept 2001" -.SH NAME -ipsec ttoaddr, tnatoaddr, addrtot \- convert Internet addresses to and from text -.br -ipsec ttosubnet, subnettot \- convert subnet/mask text form to and from addresses -.SH SYNOPSIS -.B "#include -.sp -.B "const char *ttoaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *addr);" -.br -.B "const char *tnatoaddr(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_address *addr);" -.br -.B "size_t addrtot(const ip_address *addr, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.sp -.B "const char *ttosubnet(const char *src, size_t srclen," -.ti +1c -.B "int af, ip_subnet *dst);" -.br -.B "size_t subnettot(const ip_subnet *sub, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.SH DESCRIPTION -.I Ttoaddr -converts a text-string name or numeric address into a binary address -(in network byte order). -.I Tnatoaddr -does the same conversion, -but the only text forms it accepts are -the ``official'' forms of -numeric address (dotted-decimal for IPv4, colon-hex for IPv6). -.I Addrtot -does the reverse conversion, from binary address back to a text form. -.I Ttosubnet -and -.I subnettot -do likewise for the ``address/mask'' form used to write a -specification of a subnet. -.PP -An IPv4 address is specified in text as a -dotted-decimal address (e.g. -.BR 1.2.3.4 ), -an eight-digit network-order hexadecimal number with the usual C prefix (e.g. -.BR 0x01020304 , -which is synonymous with -.BR 1.2.3.4 ), -an eight-digit host-order hexadecimal number with a -.B 0h -prefix (e.g. -.BR 0h01020304 , -which is synonymous with -.B 1.2.3.4 -on a big-endian host and -.B 4.3.2.1 -on a little-endian host), -a DNS name to be looked up via -.IR getaddrinfo (3), -or an old-style network name to be looked up via -.IR getnetbyname (3). -.PP -A dotted-decimal address may be incomplete, in which case -text-to-binary conversion implicitly appends -as many instances of -.B .0 -as necessary to bring it up to four components. -The components of a dotted-decimal address are always taken as -decimal, and leading zeros are ignored. -For example, -.B 10 -is synonymous with -.BR 10.0.0.0 , -and -.B 128.009.000.032 -is synonymous with -.BR 128.9.0.32 -(the latter example is verbatim from RFC 1166). -The result of applying -.I addrtot -to an IPv4 address is always complete and does not contain leading zeros. -.PP -Use of hexadecimal addresses is -.B strongly -.BR discouraged ; -they are included only to save hassles when dealing with -the handful of perverted programs which already print -network addresses in hexadecimal. -.PP -An IPv6 address is specified in text with -colon-hex notation (e.g. -.BR 0:56:78ab:22:33:44:55:66 ), -colon-hex with -.B :: -abbreviating at most one subsequence of multiple zeros (e.g. -.BR 99:ab::54:068 , -which is synonymous with -.BR 99:ab:0:0:0:0:54:68 ), -or a DNS name to be looked up via -.IR getaddrinfo (3). -The result of applying -.I addrtot -to an IPv6 address will use -.B :: -abbreviation if possible, -and will not contain leading zeros. -.PP -The letters in hexadecimal -may be uppercase or lowercase or any mixture thereof. -.PP -DNS names may be complete (optionally terminated with a ``.'') -or incomplete, and are looked up as specified by local system configuration -(see -.IR resolver (5)). -The first value returned by -.IR getaddrinfo (3) -is used, -so with current DNS implementations, -the result when the name corresponds to more than one address is -difficult to predict. -IPv4 name lookup resorts to -.IR getnetbyname (3) -only if -.IR getaddrinfo (3) -fails. -.PP -A subnet specification is of the form \fInetwork\fB/\fImask\fR. -The -.I network -and -.I mask -can be any form acceptable to -.IR ttoaddr . -In addition, and preferably, the -.I mask -can be a decimal integer (leading zeros ignored) giving a bit count, -in which case -it stands for a mask with that number of high bits on and all others off -(e.g., -.B 24 -in IPv4 means -.BR 255.255.255.0 ). -In any case, the mask must be contiguous -(a sequence of high bits on and all remaining low bits off). -As a special case, the subnet specification -.B %default -is a synonym for -.B 0.0.0.0/0 -or -.B ::/0 -in IPv4 or IPv6 respectively. -.PP -.I Ttosubnet -ANDs the mask with the address before returning, -so that any non-network bits in the address are turned off -(e.g., -.B 10.1.2.3/24 -is synonymous with -.BR 10.1.2.0/24 ). -.I Subnettot -always generates the decimal-integer-bit-count -form of the mask, -with no leading zeros. -.PP -The -.I srclen -parameter of -.I ttoaddr -and -.I ttosubnet -specifies the length of the text string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I af -parameter of -.I ttoaddr -and -.I ttosubnet -specifies the address family of interest. -It should be either -.B AF_INET -or -.BR AF_INET6 . -.PP -The -.I dstlen -parameter of -.I addrtot -and -.I subnettot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines constants, -.B ADDRTOT_BUF -and -.BR SUBNETTOT_BUF , -which are the sizes of buffers just large enough for worst-case results. -.PP -The -.I format -parameter of -.I addrtot -and -.I subnettot -specifies what format is to be used for the conversion. -The value -.B 0 -(not the character -.BR '0' , -but a zero value) -specifies a reasonable default, -and is in fact the only format currently available in -.IR subnettot . -.I Addrtot -also accepts format values -.B 'r' -(signifying a text form suitable for DNS reverse lookups, -e.g. -.B 4.3.2.1.IN-ADDR.ARPA. -for IPv4 and -RFC 2874 format for IPv6), -and -.B 'R' -(signifying an alternate reverse-lookup form, -an error for IPv4 and RFC 1886 format for IPv6). -Reverse-lookup names always end with a ``.''. -.PP -The text-to-binary functions return NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -The binary-to-text functions return -.B 0 -for a failure, and otherwise -always return the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.SH SEE ALSO -inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttoaddr -are: -empty input; -unknown address family; -attempt to allocate temporary storage for a very long name failed; -name lookup failed; -syntax error in dotted-decimal or colon-hex form; -dotted-decimal or colon-hex component too large. -.PP -Fatal errors in -.I ttosubnet -are: -no -.B / -in -.IR src ; -.I ttoaddr -error in conversion of -.I network -or -.IR mask ; -bit-count mask too big; -mask non-contiguous. -.PP -Fatal errors in -.I addrtot -and -.I subnettot -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The interpretation of incomplete dotted-decimal addresses -(e.g. -.B 10/24 -means -.BR 10.0.0.0/24 ) -differs from that of some older conversion -functions, e.g. those of -.IR inet (3). -The behavior of the older functions has never been -particularly consistent or particularly useful. -.PP -Ignoring leading zeros in dotted-decimal components and bit counts -is arguably the most useful behavior in this application, -but it might occasionally cause confusion with the historical use of leading -zeros to denote octal numbers. -.PP -.I Ttoaddr -does not support the mixed colon-hex-dotted-decimal -convention used to embed an IPv4 address in an IPv6 address. -.PP -.I Addrtot -always uses the -.B :: -abbreviation (which can appear only once in an address) for the -.I first -sequence of multiple zeros in an IPv6 address. -One can construct addresses (unlikely ones) in which this is suboptimal. -.PP -.I Addrtot -.B 'r' -conversion of an IPv6 address uses lowercase hexadecimal, -not the uppercase used in RFC 2874's examples. -It takes careful reading of RFCs 2874, 2673, and 2234 to realize -that lowercase is technically legitimate here, -and there may be software which botches this -and hence would have trouble with lowercase hex. -.PP -Possibly -.I subnettot -ought to recognize the -.B %default -case and generate that string as its output. -Currently it doesn't. -.PP -It is barely possible that somebody, somewhere, -might have a legitimate use for non-contiguous subnet masks. -.PP -.IR Getnetbyname (3) -is a historical dreg. -.PP -.I Tnatoaddr -probably should enforce completeness of dotted-decimal addresses. -.PP -The restriction of text-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The text-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttoaddr( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttoaddr.c b/src/libfreeswan/ttoaddr.c deleted file mode 100644 index 234c9d8e7..000000000 --- a/src/libfreeswan/ttoaddr.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * conversion from text forms of addresses to internal ones - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -/* - * Legal ASCII characters in a domain name. Underscore technically is not, - * but is a common misunderstanding. Non-ASCII characters are simply - * exempted from checking at the moment, to allow for UTF-8 encoded stuff; - * the purpose of this check is merely to catch blatant errors. - */ -static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; -#define ISASCII(c) (((c) & 0x80) == 0) - -static err_t tryname(const char *, size_t, int, int, ip_address *); -static err_t tryhex(const char *, size_t, int, ip_address *); -static err_t trydotted(const char *, size_t, ip_address *); -static err_t getbyte(const char **, const char *, int *); -static err_t colon(const char *, size_t, ip_address *); -static err_t getpiece(const char **, const char *, unsigned *); - -/* - - ttoaddr - convert text name or dotted-decimal address to binary address - */ -err_t /* NULL for success, else string literal */ -ttoaddr(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* address family */ -ip_address *dst; -{ - err_t oops; -# define HEXLEN 10 /* strlen("0x11223344") */ - int nultermd; - - if (srclen == 0) { - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - nultermd = 1; - } else - nultermd = 0; /* at least, not *known* to be terminated */ - - switch (af) { - case AF_INET: - case AF_INET6: - case 0: /* guess */ - break; - - default: - return "invalid address family"; - } - - if (af == AF_INET && srclen == HEXLEN && *src == '0') { - if (*(src+1) == 'x' || *(src+1) == 'X') - return tryhex(src+2, srclen-2, 'x', dst); - if (*(src+1) == 'h' || *(src+1) == 'H') - return tryhex(src+2, srclen-2, 'h', dst); - } - - if (memchr(src, ':', srclen) != NULL) { - if(af == 0) - { - af = AF_INET6; - } - - if (af != AF_INET6) - return "non-ipv6 address may not contain `:'"; - return colon(src, srclen, dst); - } - - if (af == 0 || af == AF_INET) { - oops = trydotted(src, srclen, dst); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* probably meant as d-d */ - } - - return tryname(src, srclen, nultermd, af, dst); -} - -/* - - tnatoaddr - convert text numeric address (only) to binary address - */ -err_t /* NULL for success, else string literal */ -tnatoaddr(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* address family */ -ip_address *dst; -{ - err_t oops; - - if (srclen == 0) { - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - } - - switch (af) { - case 0: /* guess */ - oops = colon(src, srclen, dst); - if(oops == NULL) - { - return NULL; - } - oops = trydotted(src, srclen, dst); - if(oops == NULL) - { - return NULL; - } - return "does not appear to be either IPv4 or IPv6 numeric address"; - break; - - case AF_INET6: - return colon(src, srclen, dst); - break; - case AF_INET: - oops = trydotted(src, srclen, dst); - if (oops == NULL) - return NULL; /* it worked */ - if (*oops != '?') - return oops; /* probably meant as d-d */ - return "does not appear to be numeric address"; - break; - default: - return "unknown address family in tnatoaddr"; - break; - } -} - -/* - - tryname - try it as a name - * Slightly complicated by lack of reliable NUL termination in source. - */ -static err_t -tryname(src, srclen, nultermd, af, dst) -const char *src; -size_t srclen; -int nultermd; /* is it known to be NUL-terminated? */ -int af; -ip_address *dst; -{ - struct addrinfo hints, *res; - struct netent *ne = NULL; - char namebuf[100]; /* enough for most DNS names */ - const char *cp; - char *p = namebuf; - unsigned char *addr = NULL; - size_t n; - int error; - err_t err = NULL; - - for (cp = src, n = srclen; n > 0; cp++, n--) - if (ISASCII(*cp) && strchr(namechars, *cp) == NULL) - return "illegal (non-DNS-name) character in name"; - - if (nultermd) - cp = src; - else { - if (srclen+1 > sizeof(namebuf)) { - p = (char *) MALLOC(srclen+1); - if (p == NULL) - return "unable to get temporary space for name"; - } - p[0] = '\0'; /* strncpy semantics are wrong */ - strncat(p, src, srclen); - cp = (const char *)p; - } - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = af; - error = getaddrinfo(cp, NULL, &hints, &res); - if (error != 0) - { /* getaddrinfo failed, try getnetbyname */ - if (af == AF_INET) - { - ne = getnetbyname(cp); - if (ne != NULL) - { - ne->n_net = htonl(ne->n_net); - addr = (unsigned char*)&ne->n_net; - err = initaddr(addr, sizeof(ne->n_net), af, dst); - } - } - } - else - { - struct addrinfo *r = res; - while (r) - { - size_t addr_len; - switch (r->ai_family) - { - case AF_INET: - { - struct sockaddr_in *in = (struct sockaddr_in*)r->ai_addr; - addr_len = 4; - addr = (unsigned char*)&in->sin_addr.s_addr; - break; - } - case AF_INET6: - { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)r->ai_addr; - addr_len = 16; - addr = (unsigned char*)&in6->sin6_addr.s6_addr; - break; - } - default: - { /* unknown family, try next result */ - r = r->ai_next; - continue; - } - } - err = initaddr(addr, addr_len, r->ai_family, dst); - break; - } - freeaddrinfo(res); - } - - if (p != namebuf) - { - FREE(p); - } - - if (addr == NULL) - { - return "does not look numeric and name lookup failed"; - } - - return err; -} - -/* - - tryhex - try conversion as an eight-digit hex number (AF_INET only) - */ -static err_t -tryhex(src, srclen, flavor, dst) -const char *src; -size_t srclen; /* should be 8 */ -int flavor; /* 'x' for network order, 'h' for host order */ -ip_address *dst; -{ - err_t oops; - unsigned long ul; - union { - uint32_t addr; - unsigned char buf[4]; - } u; - - if (srclen != 8) - return "internal error, tryhex called with bad length"; - - oops = ttoul(src, srclen, 16, &ul); - if (oops != NULL) - return oops; - - u.addr = (flavor == 'h') ? ul : htonl(ul); - return initaddr(u.buf, sizeof(u.buf), AF_INET, dst); -} - -/* - - trydotted - try conversion as dotted decimal (AF_INET only) - * - * If the first char of a complaint is '?', that means "didn't look like - * dotted decimal at all". - */ -static err_t -trydotted(src, srclen, dst) -const char *src; -size_t srclen; -ip_address *dst; -{ - const char *stop = src + srclen; /* just past end */ - int byte; - err_t oops; -# define NBYTES 4 - unsigned char buf[NBYTES]; - int i; - - memset(buf, 0, sizeof(buf)); - for (i = 0; i < NBYTES && src < stop; i++) { - oops = getbyte(&src, stop, &byte); - if (oops != NULL) { - if (*oops != '?') - return oops; /* bad number */ - if (i > 1) - return oops+1; /* failed number */ - return oops; /* with leading '?' */ - } - buf[i] = byte; - if (i < 3 && src < stop && *src++ != '.') { - if (i == 0) - return "?syntax error in dotted-decimal address"; - else - return "syntax error in dotted-decimal address"; - } - } - if (src != stop) - return "extra garbage on end of dotted-decimal address"; - - return initaddr(buf, sizeof(buf), AF_INET, dst); -} - -/* - - getbyte - try to scan a byte in dotted decimal - * A subtlety here is that all this arithmetic on ASCII digits really is - * highly portable -- ANSI C guarantees that digits 0-9 are contiguous. - * It's easier to just do it ourselves than set up for a call to ttoul(). - * - * If the first char of a complaint is '?', that means "didn't look like a - * number at all". - */ -err_t -getbyte(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -int *retp; /* return-value pointer */ -{ - char c; - const char *p; - int no; - - if (*srcp >= stop) - return "?empty number in dotted-decimal address"; - - no = 0; - p = *srcp; - while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') { - no = no*10 + (c - '0'); - p++; - } - if (p == *srcp) - return "?non-numeric component in dotted-decimal address"; - *srcp = p; - if (no > 255) - return "byte overflow in dotted-decimal address"; - *retp = no; - return NULL; -} - -/* - - colon - convert IPv6 "numeric" address - */ -static err_t -colon(src, srclen, dst) -const char *src; -size_t srclen; /* known to be >0 */ -ip_address *dst; -{ - const char *stop = src + srclen; /* just past end */ - unsigned piece = 0; - int gapat; /* where was empty piece seen */ - err_t oops; -# define NPIECES 8 - unsigned char buf[NPIECES*2]; /* short may have wrong byte order */ - int i; - int j; -# define IT "IPv6 numeric address" - int naftergap; - - /* leading or trailing :: becomes single empty field */ - if (*src == ':') { /* legal only if leading :: */ - if (srclen == 1 || *(src+1) != ':') - return "illegal leading `:' in " IT; - if (srclen == 2) { - unspecaddr(AF_INET6, dst); - return NULL; - } - src++; /* past first but not second */ - srclen--; - } - if (*(stop-1) == ':') { /* legal only if trailing :: */ - if (srclen == 1 || *(stop-2) != ':') - return "illegal trailing `:' in " IT; - srclen--; /* leave one */ - } - - gapat = -1; - for (i = 0; i < NPIECES && src < stop; i++) { - oops = getpiece(&src, stop, &piece); - if (oops != NULL && *oops == ':') { /* empty field */ - if (gapat >= 0) - return "more than one :: in " IT; - gapat = i; - } else if (oops != NULL) - return oops; - buf[2*i] = piece >> 8; - buf[2*i + 1] = piece & 0xff; - if (i < NPIECES-1) { /* there should be more input */ - if (src == stop && gapat < 0) - return IT " ends prematurely"; - if (src != stop && *src++ != ':') - return "syntax error in " IT; - } - } - if (src != stop) - return "extra garbage on end of " IT; - - if (gapat < 0 && i < NPIECES) /* should have been caught earlier */ - return "incomplete " IT " (internal error)"; - if (gapat >= 0 && i == NPIECES) - return "non-abbreviating empty field in " IT; - if (gapat >= 0) { - naftergap = i - (gapat + 1); - for (i--, j = NPIECES-1; naftergap > 0; i--, j--, naftergap--) { - buf[2*j] = buf[2*i]; - buf[2*j + 1] = buf[2*i + 1]; - } - for (; j >= gapat; j--) - buf[2*j] = buf[2*j + 1] = 0; - } - - return initaddr(buf, sizeof(buf), AF_INET6, dst); -} - -/* - - getpiece - try to scan one 16-bit piece of an IPv6 address - */ -err_t /* ":" means "empty field seen" */ -getpiece(srcp, stop, retp) -const char **srcp; /* *srcp is updated */ -const char *stop; /* first untouchable char */ -unsigned *retp; /* return-value pointer */ -{ - const char *p; -# define NDIG 4 - int d; - unsigned long ret; - err_t oops; - - if (*srcp >= stop || **srcp == ':') { /* empty field */ - *retp = 0; - return ":"; - } - - p = *srcp; - d = 0; - while (p < stop && d < NDIG && isxdigit(*p)) { - p++; - d++; - } - if (d == 0) - return "non-hex field in IPv6 numeric address"; - if (p < stop && d == NDIG && isxdigit(*p)) - return "field in IPv6 numeric address longer than 4 hex digits"; - - oops = ttoul(*srcp, d, 16, &ret); - if (oops != NULL) /* shouldn't happen, really... */ - return oops; - - *srcp = p; - *retp = ret; - return NULL; -} diff --git a/src/libfreeswan/ttodata.3 b/src/libfreeswan/ttodata.3 deleted file mode 100644 index 8f4b1ec93..000000000 --- a/src/libfreeswan/ttodata.3 +++ /dev/null @@ -1,280 +0,0 @@ -.TH IPSEC_TTODATA 3 "16 August 2003" -.SH NAME -ipsec ttodata, datatot \- convert binary data bytes from and to text formats -.SH SYNOPSIS -.B "#include " -.sp -.B "const char *ttodata(const char *src, size_t srclen," -.ti +1c -.B "int base, char *dst, size_t dstlen, size_t *lenp);" -.br -.B "const char *ttodatav(const char *src, size_t srclen," -.ti +1c -.B "int base, char *dst, size_t dstlen, size_t *lenp," -.ti +1c -.B "char *errp, size_t errlen, int flags);" -.br -.B "size_t datatot(const char *src, size_t srclen," -.ti +1c -.B "int format, char *dst, size_t dstlen);" -.SH DESCRIPTION -.IR Ttodata , -.IR ttodatav , -and -.I datatot -convert arbitrary binary data (e.g. encryption or authentication keys) -from and to more-or-less human-readable text formats. -.PP -Currently supported formats are hexadecimal, base64, and characters. -.PP -A hexadecimal text value begins with a -.B 0x -(or -.BR 0X ) -prefix and continues with two-digit groups -of hexadecimal digits (0-9, and a-f or A-F), -each group encoding the value of one binary byte, high-order digit first. -A single -.B _ -(underscore) -between consecutive groups is ignored, permitting punctuation to improve -readability; doing this every eight digits seems about right. -.PP -A base64 text value begins with a -.B 0s -(or -.BR 0S ) -prefix -and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /), -each group encoding the value of three binary bytes as described in -section 6.8 of RFC 2045. -If -.B flags -has the -.B TTODATAV_IGNORESPACE -bit on, blanks are ignore (after the prefix). -Note that the last one or two digits of a base64 group can be -.B = -to indicate that fewer than three binary bytes are encoded. -.PP -A character text value begins with a -.B 0t -(or -.BR 0T ) -prefix -and continues with text characters, each being the value of one binary byte. -.PP -All these functions basically copy data from -.I src -(whose size is specified by -.IR srclen ) -to -.I dst -(whose size is specified by -.IR dstlen ), -doing the conversion en route. -If the result will not fit in -.IR dst , -it is truncated; -under no circumstances are more than -.I dstlen -bytes of result written to -.IR dst . -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result bytes are written at all. -.PP -The -.I base -parameter of -.I ttodata -and -.I ttodatav -specifies what format the input is in; -normally it should be -.B 0 -to signify that this gets figured out from the prefix. -Values of -.BR 16 , -.BR 64 , -and -.BR 256 -respectively signify hexadecimal, base64, and character-text formats -without prefixes. -.PP -The -.I format -parameter of -.IR datatot , -a single character used as a type code, -specifies which text format is wanted. -The value -.B 0 -(not ASCII -.BR '0' , -but a zero value) specifies a reasonable default. -Other currently-supported values are: -.RS 2 -.TP 4 -.B 'x' -continuous lower-case hexadecimal with a -.B 0x -prefix -.TP -.B 'h' -lower-case hexadecimal with a -.B 0x -prefix and a -.B _ -every eight digits -.TP -.B ':' -lower-case hexadecimal with no prefix and a -.B : -(colon) every two digits -.TP -.B 16 -lower-case hexadecimal with no prefix or -.B _ -.TP -.B 's' -continuous base64 with a -.B 0s -prefix -.TP -.B 64 -continuous base64 with no prefix -.RE -.PP -The default format is currently -.BR 'h' . -.PP -.I Ttodata -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -On success, -if and only if -.I lenp -is non-NULL, -.B *lenp -is set to the number of bytes required to contain the full untruncated result. -It is the caller's responsibility to check this against -.I dstlen -to determine whether he has obtained a complete result. -The -.B *lenp -value is correct even if -.I dstlen -is zero, which offers a way to determine how much space would be needed -before having to allocate any. -.PP -.I Ttodatav -is just like -.I ttodata -except that in certain cases, -if -.I errp -is non-NULL, -the buffer pointed to by -.I errp -(whose length is given by -.IR errlen ) -is used to hold a more detailed error message. -The return value is NULL for success, -and is either -.I errp -or a pointer to a string literal for failure. -If the size of the error-message buffer is -inadequate for the desired message, -.I ttodatav -will fall back on returning a pointer to a literal string instead. -The -.I freeswan.h -header file defines a constant -.B TTODATAV_BUF -which is the size of a buffer large enough for worst-case results. -.PP -The normal return value of -.IR datatot -is the number of bytes required -to contain the full untruncated result. -It is the caller's responsibility to check this against -.I dstlen -to determine whether he has obtained a complete result. -The return value is correct even if -.I dstlen -is zero, which offers a way to determine how much space would be needed -before having to allocate any. -A return value of -.B 0 -signals a fatal error of some kind -(see DIAGNOSTICS). -.PP -A zero value for -.I srclen -in -.I ttodata -(but not -.IR datatot !) -is synonymous with -.BR strlen(src) . -A non-zero -.I srclen -in -.I ttodata -must not include the terminating NUL. -.PP -Unless -.I dstlen -is zero, -the result supplied by -.I datatot -is always NUL-terminated, -and its needed-size return value includes space for the terminating NUL. -.PP -Several obsolete variants of these functions -.RI ( atodata , -.IR datatoa , -.IR atobytes , -and -.IR bytestoa ) -are temporarily also supported. -.SH SEE ALSO -sprintf(3), ipsec_atoaddr(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttodata -and -.I ttodatav -are: -unknown characters in the input; -unknown or missing prefix; -unknown base; -incomplete digit group; -non-zero padding in a base64 less-than-three-bytes digit group; -zero-length input. -.PP -Fatal errors in -.I datatot -are: -unknown format code; -zero-length input. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -.I Datatot -should have a format code to produce character-text output. -.PP -The -.B 0s -and -.B 0t -prefixes are the author's inventions and are not a standard -of any kind. -They have been chosen to avoid collisions with existing practice -(some C implementations use -.B 0b -for binary) -and possible confusion with unprefixed hexadecimal. diff --git a/src/libfreeswan/ttodata.c b/src/libfreeswan/ttodata.c deleted file mode 100644 index ef3717797..000000000 --- a/src/libfreeswan/ttodata.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * convert from text form of arbitrary data (e.g., keys) to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* converters and misc */ -static int unhex(const char *, char *, size_t); -static int unb64(const char *, char *, size_t); -static int untext(const char *, char *, size_t); -static const char *badch(const char *, int, char *, size_t); - -/* internal error codes for converters */ -#define SHORT (-2) /* internal buffer too short */ -#define BADPAD (-3) /* bad base64 padding */ -#define BADCH0 (-4) /* invalid character 0 */ -#define BADCH1 (-5) /* invalid character 1 */ -#define BADCH2 (-6) /* invalid character 2 */ -#define BADCH3 (-7) /* invalid character 3 */ -#define BADOFF(code) (BADCH0-(code)) - -/* - - ttodatav - convert text to data, with verbose error reports - * If some of this looks slightly odd, it's because it has changed - * repeatedly (from the original atodata()) without a major rewrite. - */ -const char * /* NULL on success, else literal or errp */ -ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags) -const char *src; -size_t srclen; /* 0 means apply strlen() */ -int base; /* 0 means figure it out */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -size_t *lenp; /* where to record length (NULL is nowhere) */ -char *errp; /* error buffer */ -size_t errlen; -unsigned int flags; -{ - size_t ingroup; /* number of input bytes converted at once */ - char buf[4]; /* output from conversion */ - int nbytes; /* size of output */ - int (*decode)(const char *, char *, size_t); - char *stop; - int ndone; - int i; - int underscoreok; - int skipSpace = 0; - - if (srclen == 0) - srclen = strlen(src); - if (dstlen == 0) - dst = buf; /* point it somewhere valid */ - stop = dst + dstlen; - - if (base == 0) { - if (srclen < 2) - return "input too short to be valid"; - if (*src++ != '0') - return "input does not begin with format prefix"; - switch (*src++) { - case 'x': - case 'X': - base = 16; - break; - case 's': - case 'S': - base = 64; - break; - case 't': - case 'T': - base = 256; - break; - default: - return "unknown format prefix"; - } - srclen -= 2; - } - switch (base) { - case 16: - decode = unhex; - underscoreok = 1; - ingroup = 2; - break; - case 64: - decode = unb64; - underscoreok = 0; - ingroup = 4; - if(flags & TTODATAV_IGNORESPACE) { - skipSpace = 1; - } - break; - - case 256: - decode = untext; - ingroup = 1; - underscoreok = 0; - break; - default: - return "unknown base"; - } - - /* proceed */ - ndone = 0; - while (srclen > 0) { - char stage[4]; /* staging area for group */ - size_t sl = 0; - - /* Grab ingroup characters into stage, - * squeezing out blanks if we are supposed to ignore them. - */ - for (sl = 0; sl < ingroup; src++, srclen--) { - if (srclen == 0) - return "input ends in mid-byte, perhaps truncated"; - else if (!(skipSpace && (*src == ' ' || *src == '\t'))) - stage[sl++] = *src; - } - - nbytes = (*decode)(stage, buf, sizeof(buf)); - switch (nbytes) { - case BADCH0: - case BADCH1: - case BADCH2: - case BADCH3: - return badch(stage, nbytes, errp, errlen); - case SHORT: - return "internal buffer too short (\"can't happen\")"; - case BADPAD: - return "bad (non-zero) padding at end of base64 input"; - } - if (nbytes <= 0) - return "unknown internal error"; - for (i = 0; i < nbytes; i++) { - if (dst < stop) - *dst++ = buf[i]; - ndone++; - } - while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){ - src++; - srclen--; - } - if (underscoreok && srclen > 1 && *src == '_') { - /* srclen > 1 means not last character */ - src++; - srclen--; - } - } - - if (ndone == 0) - return "no data bytes specified by input"; - if (lenp != NULL) - *lenp = ndone; - return NULL; -} - -/* - - ttodata - convert text to data - */ -const char * /* NULL on success, else literal */ -ttodata(src, srclen, base, dst, dstlen, lenp) -const char *src; -size_t srclen; /* 0 means apply strlen() */ -int base; /* 0 means figure it out */ -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -size_t *lenp; /* where to record length (NULL is nowhere) */ -{ - return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL, - (size_t)0, TTODATAV_SPACECOUNTS); -} - -/* - - atodata - convert ASCII to data - * backward-compatibility interface - */ -size_t /* 0 for failure, true length for success */ -atodata(src, srclen, dst, dstlen) -const char *src; -size_t srclen; -char *dst; -size_t dstlen; -{ - size_t len; - const char *err; - - err = ttodata(src, srclen, 0, dst, dstlen, &len); - if (err != NULL) - return 0; - return len; -} - -/* - - atobytes - convert ASCII to data bytes - * another backward-compatibility interface - */ -const char * -atobytes(src, srclen, dst, dstlen, lenp) -const char *src; -size_t srclen; -char *dst; -size_t dstlen; -size_t *lenp; -{ - return ttodata(src, srclen, 0, dst, dstlen, lenp); -} - -/* - - unhex - convert two ASCII hex digits to byte - */ -static int /* number of result bytes, or error code */ -unhex(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; /* not large enough is a failure */ -{ - char *p; - unsigned byte; - static char hex[] = "0123456789abcdef"; - - if (dstlen < 1) - return SHORT; - - p = strchr(hex, *src); - if (p == NULL) - p = strchr(hex, tolower(*src)); - if (p == NULL) - return BADCH0; - byte = (p - hex) << 4; - src++; - - p = strchr(hex, *src); - if (p == NULL) - p = strchr(hex, tolower(*src)); - if (p == NULL) - return BADCH1; - byte |= (p - hex); - - *dst = byte; - return 1; -} - -/* - - unb64 - convert four ASCII base64 digits to three bytes - * Note that a base64 digit group is padded out with '=' if it represents - * less than three bytes: one byte is dd==, two is ddd=, three is dddd. - */ -static int /* number of result bytes, or error code */ -unb64(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; -{ - char *p; - unsigned byte1; - unsigned byte2; - static char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - if (dstlen < 3) - return SHORT; - - p = strchr(base64, *src++); - - if (p == NULL) - return BADCH0; - byte1 = (p - base64) << 2; /* first six bits */ - - p = strchr(base64, *src++); - if (p == NULL) { - return BADCH1; - } - - byte2 = p - base64; /* next six: two plus four */ - *dst++ = byte1 | (byte2 >> 4); - byte1 = (byte2 & 0xf) << 4; - - p = strchr(base64, *src++); - if (p == NULL) { - if (*(src-1) == '=' && *src == '=') { - if (byte1 != 0) /* bad padding */ - return BADPAD; - return 1; - } - return BADCH2; - } - - byte2 = p - base64; /* next six: four plus two */ - *dst++ = byte1 | (byte2 >> 2); - byte1 = (byte2 & 0x3) << 6; - - p = strchr(base64, *src++); - if (p == NULL) { - if (*(src-1) == '=') { - if (byte1 != 0) /* bad padding */ - return BADPAD; - return 2; - } - return BADCH3; - } - byte2 = p - base64; /* last six */ - *dst++ = byte1 | byte2; - - return 3; -} - -/* - - untext - convert one ASCII character to byte - */ -static int /* number of result bytes, or error code */ -untext(src, dst, dstlen) -const char *src; /* known to be full length */ -char *dst; -size_t dstlen; /* not large enough is a failure */ -{ - if (dstlen < 1) - return SHORT; - - *dst = *src; - return 1; -} - -/* - - badch - produce a nice complaint about an unknown character - * - * If the compiler complains that the array bigenough[] has a negative - * size, that means the TTODATAV_BUF constant has been set too small. - */ -static const char * /* literal or errp */ -badch(src, errcode, errp, errlen) -const char *src; -int errcode; -char *errp; /* might be NULL */ -size_t errlen; -{ - static const char pre[] = "unknown character (`"; - static const char suf[] = "') in input"; - char buf[5]; -# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf)) - struct sizecheck { - char bigenough[TTODATAV_BUF - REQD]; /* see above */ - }; - char ch; - - if (errp == NULL || errlen < REQD) - return "unknown character in input"; - strcpy(errp, pre); - ch = *(src + BADOFF(errcode)); - if (isprint(ch)) { - buf[0] = ch; - buf[1] = '\0'; - } else { - buf[0] = '\\'; - buf[1] = ((ch & 0700) >> 6) + '0'; - buf[2] = ((ch & 0070) >> 3) + '0'; - buf[3] = ((ch & 0007) >> 0) + '0'; - buf[4] = '\0'; - } - strcat(errp, buf); - strcat(errp, suf); - return (const char *)errp; -} - - - -#ifdef TTODATA_MAIN - -#include - -struct artab; -static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status); -static void regress(char *pgm); -static void hexout(const char *s, size_t len, FILE *f); - -/* - - main - convert first argument to hex, or run regression - */ -int -main(int argc, char *argv[]) -{ - char buf[1024]; - char buf2[1024]; - char err[512]; - size_t n; - size_t i; - char *p = buf; - char *p2 = buf2; - char *pgm = argv[0]; - const char *oops; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {0x|0s|-r}\n", pgm); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(pgm); /* should not return */ - fprintf(stderr, "%s: regress() returned?!?\n", pgm); - exit(1); - } - - oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n, - err, sizeof(err), TTODATAV_IGNORESPACE); - if (oops != NULL) { - fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm, - oops, argv[1]); - exit(1); - } - - if (n > sizeof(buf)) { - p = (char *)malloc((size_t)n); - if (p == NULL) { - fprintf(stderr, - "%s: unable to malloc %d bytes for result\n", - pgm, n); - exit(1); - } - oops = ttodata(argv[1], 0, 0, p, n, &n); - if (oops != NULL) { - fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n", - pgm, oops); - exit(1); - } - } - - hexout(p, n, stdout); - printf("\n"); - - i = datatot(buf, n, 'h', buf2, sizeof(buf2)); - if (i == 0) { - fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm, - argv[1]); - exit(1); - } - - if (i > sizeof(buf2)) { - p2 = (char *)malloc((size_t)i); - if (p == NULL) { - fprintf(stderr, - "%s: unable to malloc %d bytes for result\n", - pgm, i); - exit(1); - } - i = datatot(buf, n, 'h', p2, i); - if (i == 0) { - fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm); - exit(1); - } - } - - printf("%s\n", p2); - - exit(0); -} - -/* - - hexout - output an arbitrary-length string in hex - */ -static void -hexout(s, len, f) -const char *s; -size_t len; -FILE *f; -{ - size_t i; - - fprintf(f, "0x"); - for (i = 0; i < len; i++) - fprintf(f, "%02x", (unsigned char)s[i]); -} - -struct artab { - int base; -# define IGNORESPACE_BIAS 1000 - char *ascii; /* NULL for end */ - char *data; /* NULL for error expected */ -} atodatatab[] = { - { 0, "", NULL, }, - { 0, "0", NULL, }, - { 0, "0x", NULL, }, - { 0, "0xa", NULL, }, - { 0, "0xab", "\xab", }, - { 0, "0xabc", NULL, }, - { 0, "0xabcd", "\xab\xcd", }, - { 0, "0x0123456789", "\x01\x23\x45\x67\x89", }, - { 0, "0x01x", NULL, }, - { 0, "0xabcdef", "\xab\xcd\xef", }, - { 0, "0xABCDEF", "\xab\xcd\xef", }, - { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", }, - { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", }, - { 0, "0XaBc0_", NULL, }, - { 0, "0X_aBc0", NULL, }, - { 0, "0Xa_Bc0", NULL, }, - { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", }, - { 0, "0s", NULL, }, - { 0, "0sA", NULL, }, - { 0, "0sBA", NULL, }, - { 0, "0sCBA", NULL, }, - { 0, "0sDCBA", "\x0c\x20\x40", }, - { 0, "0SDCBA", "\x0c\x20\x40", }, - { 0, "0sDA==", "\x0c", }, - { 0, "0sDC==", NULL, }, - { 0, "0sDCA=", "\x0c\x20", }, - { 0, "0sDCB=", NULL, }, - { 0, "0sDCAZ", "\x0c\x20\x19", }, - { 0, "0sDCAa", "\x0c\x20\x1a", }, - { 0, "0sDCAz", "\x0c\x20\x33", }, - { 0, "0sDCA0", "\x0c\x20\x34", }, - { 0, "0sDCA9", "\x0c\x20\x3d", }, - { 0, "0sDCA+", "\x0c\x20\x3e", }, - { 0, "0sDCA/", "\x0c\x20\x3f", }, - { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", }, - { 0, "0t", NULL, }, - { 0, "0tabc_xyz", "abc_xyz", }, - { 256, "abc_xyz", "abc_xyz", }, - { 0, NULL, NULL, }, -}; - -struct drtab { - char *data; /* input; NULL for end */ - char format; - int buflen; /* -1 means big buffer */ - int outlen; /* -1 means strlen(ascii)+1 */ - char *ascii; /* NULL for error expected */ -} datatoatab[] = { - { "", 'x', -1, -1, NULL, }, - { "", 'X', -1, -1, NULL, }, - { "", 'n', -1, -1, NULL, }, - { "0", 'x', -1, -1, "0x30", }, - { "0", 'x', 0, 5, "---", }, - { "0", 'x', 1, 5, "", }, - { "0", 'x', 2, 5, "0", }, - { "0", 'x', 3, 5, "0x", }, - { "0", 'x', 4, 5, "0x3", }, - { "0", 'x', 5, 5, "0x30", }, - { "0", 'x', 6, 5, "0x30", }, - { "\xab\xcd", 'x', -1, -1, "0xabcd", }, - { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", }, - { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", }, - { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", }, - { "\x01\x02", 'h', -1, -1, "0x0102", }, - { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", }, - { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", }, - { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", }, - { "\x0c\x20\x40", 's', 0, 7, "---", }, - { "\x0c\x20\x40", 's', 1, 7, "", }, - { "\x0c\x20\x40", 's', 2, 7, "0", }, - { "\x0c\x20\x40", 's', 3, 7, "0s", }, - { "\x0c\x20\x40", 's', 4, 7, "0sD", }, - { "\x0c\x20\x40", 's', 5, 7, "0sDC", }, - { "\x0c\x20\x40", 's', 6, 7, "0sDCB", }, - { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", }, - { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", }, - { "\x0c", 's', -1, -1, "0sDA==", }, - { "\x0c\x20", 's', -1, -1, "0sDCA=", }, - { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", }, - { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", }, - { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", }, - { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", }, - { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", }, - { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", }, - { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", }, - { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", }, - { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", }, - { NULL, 'x', -1, -1, NULL, }, -}; - -/* - - regress - regression-test ttodata() and datatot() - */ -static void -check(r, buf, n, oops, status) -struct artab *r; -char *buf; -size_t n; -err_t oops; -int *status; -{ - if (oops != NULL && r->data == NULL) - {} /* error expected */ - else if (oops != NULL) { - printf("`%s' gave error `%s', expecting %d `", r->ascii, - oops, strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } else if (r->data == NULL) { - printf("`%s' gave %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting error\n"); - *status = 1; - } else if (n != strlen(r->data)) { - printf("length wrong in `%s': got %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting %d `", strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } else if (memcmp(buf, r->data, n) != 0) { - printf("`%s' gave %d `", r->ascii, n); - hexout(buf, n, stdout); - printf("', expecting %d `", strlen(r->data)); - hexout(r->data, strlen(r->data), stdout); - printf("'\n"); - *status = 1; - } - fflush(stdout); -} - -static void /* should not return at all, in fact */ -regress(pgm) -char *pgm; -{ - struct artab *r; - struct drtab *dr; - char buf[100]; - size_t n; - int status = 0; - - for (r = atodatatab; r->ascii != NULL; r++) { - int base = r->base; - int xbase = 0; - - if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') { - switch (r->ascii[1]) { - case 'x': - case 'X': - xbase = 16; - break; - case 's': - case 'S': - xbase = 64; - break; - case 't': - case 'T': - xbase = 256; - break; - } - } - - if (base >= IGNORESPACE_BIAS) { - base = base - IGNORESPACE_BIAS; - check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - if (xbase != 0) - check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - } else { - check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status); - if (base == 64 || xbase == 64) - check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - if (xbase != 0) { - check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status); - if (base == 64 || xbase == 64) - check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status); - } - } - } - for (dr = datatoatab; dr->data != NULL; dr++) { - size_t should; - - strcpy(buf, "---"); - n = datatot(dr->data, strlen(dr->data), dr->format, buf, - (dr->buflen == -1) ? sizeof(buf) : dr->buflen); - should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1; - if (dr->outlen != -1) - should = dr->outlen; - if (n == 0 && dr->ascii == NULL) - {} /* error expected */ - else if (n == 0) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' %c gave error, expecting %d `%s'\n", - dr->format, should, dr->ascii); - status = 1; - } else if (dr->ascii == NULL) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' %c gave %d `%.*s', expecting error\n", - dr->format, n, (int)n, buf); - status = 1; - } else if (n != should) { - printf("length wrong in `"); - hexout(dr->data, strlen(dr->data), stdout); - printf("': got %d `%s'", n, buf); - printf(", expecting %d `%s'\n", should, dr->ascii); - status = 1; - } else if (strcmp(buf, dr->ascii) != 0) { - printf("`"); - hexout(dr->data, strlen(dr->data), stdout); - printf("' gave %d `%s'", n, buf); - printf(", expecting %d `%s'\n", should, dr->ascii); - status = 1; - } - fflush(stdout); - } - exit(status); -} - -#endif /* TTODATA_MAIN */ diff --git a/src/libfreeswan/ttoprotoport.c b/src/libfreeswan/ttoprotoport.c deleted file mode 100644 index e75b206be..000000000 --- a/src/libfreeswan/ttoprotoport.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * conversion from protocol/port string to protocol and port - * Copyright (C) 2002 Mario Strasser , - * Zuercher Hochschule Winterthur, - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "internal.h" -#include "freeswan.h" - -/* - * ttoprotoport - converts from protocol/port string to protocol and port - */ -err_t -ttoprotoport(src, src_len, proto, port, has_port_wildcard) -char *src; /* input string */ -size_t src_len; /* length of input string, use strlen() if 0 */ -u_int8_t *proto; /* extracted protocol number */ -u_int16_t *port; /* extracted port number if it exists */ -bool *has_port_wildcard; /* set if port is %any */ -{ - char *end, *service_name; - char proto_name[16]; - int proto_len; - long int l; - struct protoent *protocol; - struct servent *service; - - /* get the length of the string */ - if (!src_len) src_len = strlen(src); - - /* locate delimiter '/' between protocol and port */ - end = strchr(src, '/'); - if (end != NULL) { - proto_len = end - src; - service_name = end + 1; - } else { - proto_len = src_len; - service_name = src + src_len; - } - - /* copy protocol name*/ - memset(proto_name, '\0', sizeof(proto_name)); - memcpy(proto_name, src, proto_len); - - /* extract protocol by trying to resolve it by name */ - protocol = getprotobyname(proto_name); - if (protocol != NULL) { - *proto = protocol->p_proto; - } - else /* failed, now try it by number */ - { - l = strtol(proto_name, &end, 0); - - if (*proto_name && *end) - return " is neither a number nor a valid name"; - - if (l < 0 || l > 0xff) - return " must be between 0 and 255"; - - *proto = (u_int8_t)l; - } - - /* is there a port wildcard? */ - *has_port_wildcard = (strcmp(service_name, "%any") == 0); - - if (*has_port_wildcard) - { - *port = 0; - return NULL; - } - - /* extract port by trying to resolve it by name */ - service = getservbyname(service_name, NULL); - if (service != NULL) { - *port = ntohs(service->s_port); - } - else /* failed, now try it by number */ - { - l = strtol(service_name, &end, 0); - - if (*service_name && *end) - return " is neither a number nor a valid name"; - - if (l < 0 || l > 0xffff) - return " must be between 0 and 65535"; - - *port = (u_int16_t)l; - } - return NULL; -} - diff --git a/src/libfreeswan/ttosa.3 b/src/libfreeswan/ttosa.3 deleted file mode 100644 index f9ea36a09..000000000 --- a/src/libfreeswan/ttosa.3 +++ /dev/null @@ -1,287 +0,0 @@ -.TH IPSEC_TTOSA 3 "26 Nov 2001" -.SH NAME -ipsec ttosa, satot \- convert IPsec Security Association IDs to and from text -.br -ipsec initsaid \- initialize an SA ID -.SH SYNOPSIS -.B "#include -.sp -.B "typedef struct {" -.ti +1c -.B "ip_address dst;" -.ti +1c -.B "ipsec_spi_t spi;" -.ti +1c -.B "int proto;" -.br -.B "} ip_said;" -.sp -.B "const char *ttosa(const char *src, size_t srclen," -.ti +1c -.B "ip_said *sa); -.br -.B "size_t satot(const ip_said *sa, int format," -.ti +1c -.B "char *dst, size_t dstlen);" -.br -.B "void initsaid(const ip_address *addr, ipsec_spi_t spi," -.ti +1c -.B "int proto, ip_said *dst);" -.SH DESCRIPTION -.I Ttosa -converts an ASCII Security Association (SA) specifier into an -.B ip_said -structure (containing -a destination-host address -in network byte order, -an SPI number in network byte order, and -a protocol code). -.I Satot -does the reverse conversion, back to a text SA specifier. -.I Initsaid -initializes an -.B ip_said -from separate items of information. -.PP -An SA is specified in text with a mail-like syntax, e.g. -.BR esp.5a7@1.2.3.4 . -An SA specifier contains -a protocol prefix (currently -.BR ah , -.BR esp , -.BR tun , -.BR comp , -or -.BR int ), -a single character indicating the address family -.RB ( . -for IPv4, -.B : -for IPv6), -an unsigned integer SPI number in hexadecimal (with no -.B 0x -prefix), -and an IP address. -The IP address can be any form accepted by -.IR ipsec_ttoaddr (3), -e.g. dotted-decimal IPv4 address, -colon-hex IPv6 address, -or DNS name. -.PP -As a special case, the SA specifier -.B %passthrough4 -or -.B %passthrough6 -signifies the special SA used to indicate that packets should be -passed through unaltered. -(At present, these are synonyms for -.B tun.0@0.0.0.0 -and -.B tun:0@:: -respectively, -but that is subject to change without notice.) -.B %passthrough -is a historical synonym for -.BR %passthrough4 . -These forms are known to both -.I ttosa -and -.IR satot , -so the internal representation is never visible. -.PP -Similarly, the SA specifiers -.BR %pass , -.BR %drop , -.BR %reject , -.BR %hold , -.BR %trap , -and -.BR %trapsubnet -signify special ``magic'' SAs used to indicate that packets should be -passed, dropped, rejected (dropped with ICMP notification), -held, -and trapped (sent up to -.IR ipsec_pluto (8), -with either of two forms of -.B %hold -automatically installed) -respectively. -These forms too are known to both routines, -so the internal representation of the magic SAs should never be visible. -.PP -The -.B -header file supplies the -.B ip_said -structure, as well as a data type -.B ipsec_spi_t -which is an unsigned 32-bit integer. -(There is no consistency between kernel and user on what such a type -is called, hence the header hides the differences.) -.PP -The protocol code uses the same numbers that IP does. -For user convenience, given the difficulty in acquiring the exact set of -protocol names used by the kernel, -.B -defines the names -.BR SA_ESP , -.BR SA_AH , -.BR SA_IPIP , -and -.BR SA_COMP -to have the same values as the kernel names -.BR IPPROTO_ESP , -.BR IPPROTO_AH , -.BR IPPROTO_IPIP , -and -.BR IPPROTO_COMP . -.PP -.B -also defines -.BR SA_INT -to have the value -.BR 61 -(reserved by IANA for ``any host internal protocol'') -and -.BR SPI_PASS , -.BR SPI_DROP , -.BR SPI_REJECT , -.BR SPI_HOLD , -and -.B SPI_TRAP -to have the values 256-260 (in \fIhost\fR byte order) respectively. -These are used in constructing the magic SAs -(which always have address -.BR 0.0.0.0 ). -.PP -If -.I satot -encounters an unknown protocol code, e.g. 77, -it yields output using a prefix -showing the code numerically, e.g. ``unk77''. -This form is -.I not -recognized by -.IR ttosa . -.PP -The -.I srclen -parameter of -.I ttosa -specifies the length of the string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I dstlen -parameter of -.I satot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.B -header file defines a constant, -.BR SATOT_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I satot -specifies what format is to be used for the conversion. -The value -.B 0 -(not the ASCII character -.BR '0' , -but a zero value) -specifies a reasonable default -(currently -lowercase protocol prefix, lowercase hexadecimal SPI, -dotted-decimal or colon-hex address). -The value -.B 'f' -is similar except that the SPI is padded with -.BR 0 s -to a fixed 32-bit width, to ease aligning displayed tables. -.PP -.I Ttosa -returns -.B NULL -for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Satot -returns -.B 0 -for a failure, and otherwise -always returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL; -it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred. -.PP -There is also, temporarily, support for some obsolete -forms of SA specifier which lack the address-family indicator. -.SH SEE ALSO -ipsec_ttoul(3), ipsec_ttoaddr(3), ipsec_samesaid(3), inet(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttosa -are: -empty input; -input too small to be a legal SA specifier; -no -.B @ -in input; -unknown protocol prefix; -conversion error in -.I ttoul -or -.IR ttoaddr . -.PP -Fatal errors in -.I satot -are: -unknown format. -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -The restriction of text-to-binary error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The text-to-binary error-reporting convention lends itself -to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttosa( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttosa.c b/src/libfreeswan/ttosa.c deleted file mode 100644 index 9873231c0..000000000 --- a/src/libfreeswan/ttosa.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * convert from text form of SA ID to binary - * Copyright (C) 2000, 2001 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -static struct satype { - char *prefix; - size_t prelen; /* strlen(prefix) */ - int proto; -} satypes[] = { - { "ah", 2, SA_AH }, - { "esp", 3, SA_ESP }, - { "tun", 3, SA_IPIP }, - { "comp", 4, SA_COMP }, - { "int", 3, SA_INT }, - { NULL, 0, 0, } -}; - -static struct magic { - char *name; - char *really; -} magic[] = { - { PASSTHROUGHNAME, PASSTHROUGH4IS }, - { PASSTHROUGH4NAME, PASSTHROUGH4IS }, - { PASSTHROUGH6NAME, PASSTHROUGH6IS }, - { "%pass", "int256@0.0.0.0" }, - { "%drop", "int257@0.0.0.0" }, - { "%reject", "int258@0.0.0.0" }, - { "%hold", "int259@0.0.0.0" }, - { "%trap", "int260@0.0.0.0" }, - { "%trapsubnet", "int261@0.0.0.0" }, - { NULL, NULL } -}; - -/* - - ttosa - convert text "ah507@10.0.0.1" to SA identifier - */ -err_t /* NULL for success, else string literal */ -ttosa(src, srclen, sa) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -ip_said *sa; -{ - const char *at; - const char *addr; - size_t alen; - const char *spi = NULL; - struct satype *sat; - unsigned long ul; - const char *oops; - struct magic *mp; - size_t nlen; -# define MINLEN 5 /* ah0@0 is as short as it can get */ - int af; - int base; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - if (srclen < MINLEN) - return "string too short to be SA identifier"; - if (*src == '%') { - for (mp = magic; mp->name != NULL; mp++) { - nlen = strlen(mp->name); - if (srclen == nlen && memcmp(src, mp->name, nlen) == 0) - break; - } - if (mp->name == NULL) - return "unknown % keyword"; - src = mp->really; - srclen = strlen(src); - } - - at = memchr(src, '@', srclen); - if (at == NULL) - return "no @ in SA specifier"; - - for (sat = satypes; sat->prefix != NULL; sat++) - if (sat->prelen < srclen && - strncmp(src, sat->prefix, sat->prelen) == 0) { - sa->proto = sat->proto; - spi = src + sat->prelen; - break; /* NOTE BREAK OUT */ - } - if (sat->prefix == NULL) - return "SA specifier lacks valid protocol prefix"; - - if (spi >= at) - return "no SPI in SA specifier"; - switch (*spi) { - case '.': - af = AF_INET; - spi++; - base = 16; - break; - case ':': - af = AF_INET6; - spi++; - base = 16; - break; - default: - af = AF_UNSPEC; /* not known yet */ - base = 0; - break; - } - if (spi >= at) - return "no SPI found in SA specifier"; - oops = ttoul(spi, at - spi, base, &ul); - if (oops != NULL) - return oops; - sa->spi = htonl(ul); - - addr = at + 1; - alen = srclen - (addr - src); - if (af == AF_UNSPEC) - af = (memchr(addr, ':', alen) != NULL) ? AF_INET6 : AF_INET; - oops = ttoaddr(addr, alen, af, &sa->dst); - if (oops != NULL) - return oops; - - return NULL; -} - - - -#ifdef TTOSA_MAIN - -#include - -void regress(void); - -int -main(int argc, char *argv[]) -{ - ip_said sa; - char buf[100]; - char buf2[100]; - const char *oops; - size_t n; - - if (argc < 2) { - fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - oops = ttosa(argv[1], 0, &sa); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = satot(&sa, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto); - fprintf(stderr, "%lx@", (long unsigned int)sa.spi); - (void) addrtot(&sa.dst, 0, buf2, sizeof(buf2)); - fprintf(stderr, "%s", buf2); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int format; -# define FUDGE 0x1000 - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {0, "esp257@1.2.3.0", "esp.101@1.2.3.0"}, - {0, "ah0x20@1.2.3.4", "ah.20@1.2.3.4"}, - {0, "tun20@1.2.3.4", "tun.14@1.2.3.4"}, - {0, "comp20@1.2.3.4", "comp.14@1.2.3.4"}, - {0, "esp257@::1", "esp:101@::1"}, - {0, "esp257@0bc:12de::1", "esp:101@bc:12de::1"}, - {0, "esp78@1049:1::8007:2040", "esp:4e@1049:1::8007:2040"}, - {0, "esp0x78@1049:1::8007:2040", "esp:78@1049:1::8007:2040"}, - {0, "ah78@1049:1::8007:2040", "ah:4e@1049:1::8007:2040"}, - {0, "ah0x78@1049:1::8007:2040", "ah:78@1049:1::8007:2040"}, - {0, "tun78@1049:1::8007:2040", "tun:4e@1049:1::8007:2040"}, - {0, "tun0x78@1049:1::8007:2040", "tun:78@1049:1::8007:2040"}, - {0, "duk99@3ffe:370:400:ff::9001:3001", NULL}, - {0, "esp78x@1049:1::8007:2040", NULL}, - {0, "esp0x78@1049:1:0xfff::8007:2040", NULL}, - {0, "es78@1049:1::8007:2040", NULL}, - {0, "", NULL}, - {0, "_", NULL}, - {0, "ah2.2", NULL}, - {0, "goo2@1.2.3.4", NULL}, - {0, "esp9@1.2.3.4", "esp.9@1.2.3.4"}, - {'f', "esp0xa9@1.2.3.4", "esp.000000a9@1.2.3.4"}, - {0, "espp9@1.2.3.4", NULL}, - {0, "es9@1.2.3.4", NULL}, - {0, "ah@1.2.3.4", NULL}, - {0, "esp7x7@1.2.3.4", NULL}, - {0, "esp77@1.0x2.3.4", NULL}, - {0, PASSTHROUGHNAME, PASSTHROUGH4NAME}, - {0, PASSTHROUGH6NAME, PASSTHROUGH6NAME}, - {0, "%pass", "%pass"}, - {0, "int256@0.0.0.0", "%pass"}, - {0, "%drop", "%drop"}, - {0, "int257@0.0.0.0", "%drop"}, - {0, "%reject", "%reject"}, - {0, "int258@0.0.0.0", "%reject"}, - {0, "%hold", "%hold"}, - {0, "int259@0.0.0.0", "%hold"}, - {0, "%trap", "%trap"}, - {0, "int260@0.0.0.0", "%trap"}, - {0, "%trapsubnet", "%trapsubnet"}, - {0, "int261@0.0.0.0", "%trapsubnet"}, - {0, "int262@0.0.0.0", "int.106@0.0.0.0"}, - {FUDGE, "esp9@1.2.3.4", "unk77.9@1.2.3.4"}, - {0, NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - ip_said sa; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - - for (r = rtab; r->input != NULL; r++) { - strcpy(in, r->input); - oops = ttosa(in, 0, &sa); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' ttosa failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' ttosa succeeded unexpectedly\n", - r->input); - status = 1; - } else { - if (r->format&FUDGE) - sa.proto = 77; - n = satot(&sa, (char)r->format, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' satot failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* TTOSA_MAIN */ diff --git a/src/libfreeswan/ttosubnet.c b/src/libfreeswan/ttosubnet.c deleted file mode 100644 index a18a3f326..000000000 --- a/src/libfreeswan/ttosubnet.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * convert from text form of subnet specification to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include - -#include "internal.h" -#include "freeswan.h" - -#ifndef DEFAULTSUBNET -#define DEFAULTSUBNET "%default" -#endif - -/* - - ttosubnet - convert text "addr/mask" to address and mask - * Mask can be integer bit count. - */ -err_t -ttosubnet(src, srclen, af, dst) -const char *src; -size_t srclen; /* 0 means "apply strlen" */ -int af; /* AF_INET or AF_INET6 */ -ip_subnet *dst; -{ - const char *slash; - const char *colon; - const char *mask; - size_t mlen; - const char *oops; - unsigned long bc; - static char def[] = DEFAULTSUBNET; -# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */ - static char defis4[] = "0/0"; -# define DEFIS4LEN (sizeof(defis4) - 1) - static char defis6[] = "::/0"; -# define DEFIS6LEN (sizeof(defis6) - 1) - ip_address addrtmp; - ip_address masktmp; - int nbits; - int i; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - switch (af) { - case AF_INET: - nbits = 32; - break; - case AF_INET6: - nbits = 128; - break; - default: - return "unknown address family in ttosubnet"; - break; - } - - if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) { - src = (af == AF_INET) ? defis4 : defis6; - srclen = (af == AF_INET) ? DEFIS4LEN : DEFIS6LEN; - } - - slash = memchr(src, '/', srclen); - if (slash == NULL) - return "no / in subnet specification"; - mask = slash + 1; - mlen = srclen - (mask - src); - - oops = ttoaddr(src, slash-src, af, &addrtmp); - if (oops != NULL) - return oops; - - /* extract port */ - colon = memchr(mask, ':', mlen); - if (colon == 0) - { - setportof(0, &addrtmp); - } - else - { - long port; - - oops = ttoul(colon+1, mlen-(colon-mask+1), 10, &port); - if (oops != NULL) - return oops; - setportof(htons(port), &addrtmp); - mlen = colon - mask; - } - - /*extract mask */ - oops = ttoul(mask, mlen, 10, &bc); - if (oops == NULL) { - /* ttoul succeeded, it's a bit-count mask */ - if (bc > nbits) - return "subnet mask bit count too large"; - i = bc; - } else { - oops = ttoaddr(mask, mlen, af, &masktmp); - if (oops != NULL) - return oops; - i = masktocount(&masktmp); - if (i < 0) - return "non-contiguous or otherwise erroneous mask"; - } - - return initsubnet(&addrtmp, i, '0', dst); -} - - - -#ifdef TTOSUBNET_MAIN - -#include - -void regress(void); - -int main(int argc, char *argv[]) -{ - ip_subnet s; - char buf[100]; - char buf2[100]; - const char *oops; - size_t n; - int af; - char *p; - - if (argc < 2) { - fprintf(stderr, "Usage: %s [-6] addr/mask\n", argv[0]); - fprintf(stderr, " or: %s -r\n", argv[0]); - exit(2); - } - - if (strcmp(argv[1], "-r") == 0) { - regress(); - fprintf(stderr, "regress() returned?!?\n"); - exit(1); - } - - af = AF_INET; - p = argv[1]; - if (strcmp(argv[1], "-6") == 0) { - af = AF_INET6; - p = argv[2]; - } else if (strchr(argv[1], ':') != NULL) - af = AF_INET6; - - oops = ttosubnet(p, 0, af, &s); - if (oops != NULL) { - fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops); - exit(1); - } - n = subnettot(&s, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - fprintf(stderr, "%s: reverse conversion of ", argv[0]); - (void) addrtot(&s.addr, 0, buf2, sizeof(buf2)); - fprintf(stderr, "%s/", buf2); - fprintf(stderr, "%d", s.maskbits); - fprintf(stderr, " failed: need %ld bytes, have only %ld\n", - (long)n, (long)sizeof(buf)); - exit(1); - } - printf("%s\n", buf); - - exit(0); -} - -struct rtab { - int family; - char *input; - char *output; /* NULL means error expected */ -} rtab[] = { - {4, "1.2.3.0/255.255.255.0", "1.2.3.0/24"}, - {4, "1.2.3.0/24", "1.2.3.0/24"}, - {4, "1.2.3.0/24:10", "1.2.3.0/24:10"}, - {4, "1.2.3.0/24:-1", NULL}, - {4, "1.2.3.0/24:none", NULL}, - {4, "1.2.3.0/24:", NULL}, - {4, "1.2.3.0/24:0x10", "1.2.3.0/24:16"}, - {4, "1.2.3.0/24:0X10", "1.2.3.0/24:16"}, - {4, "1.2.3.0/24:010", "1.2.3.0/24:8"}, - {4, "1.2.3.1/255.255.255.240", "1.2.3.0/28"}, - {4, "1.2.3.1/32", "1.2.3.1/32"}, - {4, "1.2.3.1/0", "0.0.0.0/0"}, -/* {4, "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0"}, */ - {4, "1.2.3.1/255.255.127.0", NULL}, - {4, "128.009.000.032/32", "128.9.0.32/32"}, - {4, "128.0x9.0.32/32", NULL}, - {4, "0x80090020/32", "128.9.0.32/32"}, - {4, "0x800x0020/32", NULL}, - {4, "128.9.0.32/0xffFF0000", "128.9.0.0/16"}, - {4, "128.9.0.32/0xff0000FF", NULL}, - {4, "128.9.0.32/0x0000ffFF", NULL}, - {4, "128.9.0.32/0x00ffFF0000", NULL}, - {4, "128.9.0.32/0xffFF", NULL}, - {4, "128.9.0.32.27/32", NULL}, - {4, "128.9.0k32/32", NULL}, - {4, "328.9.0.32/32", NULL}, - {4, "128.9..32/32", NULL}, - {4, "10/8", "10.0.0.0/8"}, - {4, "10.0/8", "10.0.0.0/8"}, - {4, "10.0.0/8", "10.0.0.0/8"}, - {4, "10.0.1/24", "10.0.1.0/24"}, - {4, "_", NULL}, - {4, "_/_", NULL}, - {4, "1.2.3.1", NULL}, - {4, "1.2.3.1/_", NULL}, - {4, "1.2.3.1/24._", NULL}, - {4, "1.2.3.1/99", NULL}, - {4, "localhost/32", "127.0.0.1/32"}, - {4, "%default", "0.0.0.0/0"}, - {6, "3049:1::8007:2040/0", "::/0"}, - {6, "3049:1::8007:2040/128", "3049:1::8007:2040/128"}, - {6, "3049:1::192.168.0.1/128", NULL}, /*"3049:1::c0a8:1/128",*/ - {6, "3049:1::8007::2040/128", NULL}, - {6, "3049:1::8007:2040/ffff::0", "3049::/16"}, - {6, "3049:1::8007:2040/64", "3049:1::/64"}, - {6, "3049:1::8007:2040/ffff::", "3049::/16"}, - {6, "3049:1::8007:2040/0000:ffff::0", NULL}, - {6, "3049:1::8007:2040/ff1f::0", NULL}, - {6, "3049:1::8007:x:2040/128", NULL}, - {6, "3049:1t::8007:2040/128", NULL}, - {6, "3049:1::80071:2040/128", NULL}, - {6, "::/21", "::/21"}, - {6, "::1/128", "::1/128"}, - {6, "1::/21", "1::/21"}, - {6, "1::2/128", "1::2/128"}, - {6, "1:0:0:0:0:0:0:2/128", "1::2/128"}, - {6, "1:0:0:0:3:0:0:2/128", "1::3:0:0:2/128"}, - {6, "1:0:0:3:0:0:0:2/128", "1::3:0:0:0:2/128"}, - {6, "1:0:3:0:0:0:0:2/128", "1:0:3::2/128"}, - {6, "abcd:ef01:2345:6789:0:00a:000:20/128", "abcd:ef01:2345:6789:0:a:0:20/128"}, - {6, "3049:1::8007:2040/ffff:ffff:", NULL}, - {6, "3049:1::8007:2040/ffff:88::", NULL}, - {6, "3049:12::9000:3200/ffff:fff0::", "3049:10::/28"}, - {6, "3049:12::9000:3200/28", "3049:10::/28"}, - {6, "3049:12::9000:3200/ff00:::", NULL}, - {6, "3049:12::9000:3200/ffff:::", NULL}, - {6, "3049:12::9000:3200/128_", NULL}, - {6, "3049:12::9000:3200/", NULL}, - {6, "%default", "::/0"}, - {4, NULL, NULL} -}; - -void -regress(void) -{ - struct rtab *r; - int status = 0; - ip_subnet s; - char in[100]; - char buf[100]; - const char *oops; - size_t n; - int af; - - for (r = rtab; r->input != NULL; r++) { - af = (r->family == 4) ? AF_INET : AF_INET6; - strcpy(in, r->input); - oops = ttosubnet(in, 0, af, &s); - if (oops != NULL && r->output == NULL) - {} /* okay, error expected */ - else if (oops != NULL) { - printf("`%s' ttosubnet failed: %s\n", r->input, oops); - status = 1; - } else if (r->output == NULL) { - printf("`%s' ttosubnet succeeded unexpectedly\n", - r->input); - status = 1; - } else { - n = subnettot(&s, 0, buf, sizeof(buf)); - if (n > sizeof(buf)) { - printf("`%s' subnettot failed: need %ld\n", - r->input, (long)n); - status = 1; - } else if (strcmp(r->output, buf) != 0) { - printf("`%s' gave `%s', expected `%s'\n", - r->input, buf, r->output); - status = 1; - } - } - } - exit(status); -} - -#endif /* TTOSUBNET_MAIN */ diff --git a/src/libfreeswan/ttoul.3 b/src/libfreeswan/ttoul.3 deleted file mode 100644 index ffd9fb38a..000000000 --- a/src/libfreeswan/ttoul.3 +++ /dev/null @@ -1,191 +0,0 @@ -.TH IPSEC_TTOUL 3 "16 Aug 2000" -.SH NAME -ipsec ttoul, ultot \- convert unsigned-long numbers to and from text -.SH SYNOPSIS -.B "#include -.sp -.B "const char *ttoul(const char *src, size_t srclen," -.ti +1c -.B "int base, unsigned long *n);" -.br -.B "size_t ultot(unsigned long n, int format, char *dst," -.ti +1c -.B "size_t dstlen);" -.SH DESCRIPTION -.I Ttoul -converts a text-string number into a binary -.B "unsigned long" -value. -.I Ultot -does the reverse conversion, back to a text version. -.PP -Numbers are specified in text as -decimal (e.g. -.BR 123 ), -octal with a leading zero (e.g. -.BR 012 , -which has value 10), -or hexadecimal with a leading -.B 0x -(e.g. -.BR 0x1f , -which has value 31) -in either upper or lower case. -.PP -The -.I srclen -parameter of -.I ttoul -specifies the length of the string pointed to by -.IR src ; -it is an error for there to be anything else -(e.g., a terminating NUL) within that length. -As a convenience for cases where an entire NUL-terminated string is -to be converted, -a -.I srclen -value of -.B 0 -is taken to mean -.BR strlen(src) . -.PP -The -.I base -parameter of -.I ttoul -can be -.BR 8 , -.BR 10 , -or -.BR 16 , -in which case the number supplied is assumed to be of that form -(and in the case of -.BR 16 , -to lack any -.B 0x -prefix). -It can also be -.BR 0 , -in which case the number is examined for a leading zero -or a leading -.B 0x -to determine its base. -.PP -The -.I dstlen -parameter of -.I ultot -specifies the size of the -.I dst -parameter; -under no circumstances are more than -.I dstlen -bytes written to -.IR dst . -A result which will not fit is truncated. -.I Dstlen -can be zero, in which case -.I dst -need not be valid and no result is written, -but the return value is unaffected; -in all other cases, the (possibly truncated) result is NUL-terminated. -The -.I freeswan.h -header file defines a constant, -.BR ULTOT_BUF , -which is the size of a buffer just large enough for worst-case results. -.PP -The -.I format -parameter of -.I ultot -must be one of: -.RS -.IP \fB'o'\fR 4 -octal conversion with leading -.B 0 -.IP \fB\ 8\fR -octal conversion with no leading -.B 0 -.IP \fB'd'\fR -decimal conversion -.IP \fB10\fR -same as -.B d -.IP \fB'x'\fR -hexadecimal conversion, including leading -.B 0x -.IP \fB16\fR -hexadecimal conversion with no leading -.B 0x -.IP \fB17\fR -like -.B 16 -except padded on left with -.BR 0 s -to eight digits (full width of a 32-bit number) -.RE -.PP -.I Ttoul -returns NULL for success and -a pointer to a string-literal error message for failure; -see DIAGNOSTICS. -.I Ultot -returns -.B 0 -for a failure, and otherwise -returns the size of buffer which would -be needed to -accommodate the full conversion result, including terminating NUL -(it is the caller's responsibility to check this against the size of -the provided buffer to determine whether truncation has occurred). -.SH SEE ALSO -atol(3), strtoul(3) -.SH DIAGNOSTICS -Fatal errors in -.I ttoul -are: -empty input; -unknown -.IR base ; -non-digit character found; -number too large for an -.BR "unsigned long" . -.PP -Fatal errors in -.I ultot -are: -unknown -.IR format . -.SH HISTORY -Written for the FreeS/WAN project by Henry Spencer. -.SH BUGS -Conversion of -.B 0 -with format -.B o -yields -.BR 00 . -.PP -.I Ultot -format -.B 17 -is a bit of a kludge. -.PP -The restriction of error reports to literal strings -(so that callers don't need to worry about freeing them or copying them) -does limit the precision of error reporting. -.PP -The error-reporting convention lends itself to slightly obscure code, -because many readers will not think of NULL as signifying success. -A good way to make it clearer is to write something like: -.PP -.RS -.nf -.B "const char *error;" -.sp -.B "error = ttoul( /* ... */ );" -.B "if (error != NULL) {" -.B " /* something went wrong */" -.fi -.RE diff --git a/src/libfreeswan/ttoul.c b/src/libfreeswan/ttoul.c deleted file mode 100644 index 7524789c4..000000000 --- a/src/libfreeswan/ttoul.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * convert from text form of unsigned long to binary - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ttoul - convert text substring to unsigned long number - */ -const char * /* NULL for success, else string literal */ -ttoul(src, srclen, base, resultp) -const char *src; -size_t srclen; /* 0 means strlen(src) */ -int base; /* 0 means figure it out */ -unsigned long *resultp; -{ - const char *stop; - static char hex[] = "0123456789abcdef"; - static char uchex[] = "0123456789ABCDEF"; - int d; - char c; - char *p; - unsigned long r; - unsigned long rlimit; - int dlimit; - - if (srclen == 0) - srclen = strlen(src); - if (srclen == 0) - return "empty string"; - - if (base == 0) { - if (srclen > 2 && *src == '0' && - (*(src+1) == 'x' || *(src+1) == 'X')) - return ttoul(src+2, srclen-2, 16, resultp); - if (srclen > 1 && *src == '0') - return ttoul(src+1, srclen-1, 8, resultp); - return ttoul(src, srclen, 10, resultp); - } - if (base != 8 && base != 10 && base != 16) - return "unsupported number base"; - - r = 0; - stop = src + srclen; - if (base == 16) { - while (src < stop) { - c = *src++; - p = strchr(hex, c); - if (p != NULL) - d = p - hex; - else { - p = strchr(uchex, c); - if (p == NULL) - return "non-hex digit in hex number"; - d = p - uchex; - } - r = (r << 4) | d; - } - /* defer length check to catch invalid digits first */ - if (srclen > sizeof(unsigned long) * 2) - return "hex number too long"; - } else { - rlimit = ULONG_MAX / base; - dlimit = (int)(ULONG_MAX - rlimit*base); - while (src < stop) { - c = *src++; - d = c - '0'; - if (d < 0 || d >= base) - return "non-digit in number"; - if (r > rlimit || (r == rlimit && d > dlimit)) - return "unsigned-long overflow"; - r = r*base + d; - } - } - - *resultp = r; - return NULL; -} diff --git a/src/libfreeswan/ultoa.c b/src/libfreeswan/ultoa.c deleted file mode 100644 index 16ddd2c1e..000000000 --- a/src/libfreeswan/ultoa.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * convert unsigned long to ASCII - * Copyright (C) 1998, 1999 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ultoa - convert unsigned long to decimal ASCII - */ -size_t /* length required for full conversion */ -ultoa(n, base, dst, dstlen) -unsigned long n; -int base; -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - char buf[3*sizeof(unsigned long) + 1]; - char *bufend = buf + sizeof(buf); - size_t len; - char *p; - static char hex[] = "0123456789abcdef"; - - p = bufend; - *--p = '\0'; - if (base == 10) { - do { - *--p = n%10 + '0'; - n /= 10; - } while (n != 0); - } else if (base == 16) { - do { - *--p = hex[n&0xf]; - n >>= 4; - } while (n != 0); - *--p = 'x'; - *--p = '0'; - } else if (base == 8) { - do { - *--p = (n&07) + '0'; - n >>= 3; - } while (n != 0); - *--p = '0'; - } else - *--p = '?'; - - len = bufend - p; - - if (dstlen > 0) { - if (len > dstlen) - *(p + dstlen - 1) = '\0'; - strcpy(dst, p); - } - return len; -} diff --git a/src/libfreeswan/ultot.c b/src/libfreeswan/ultot.c deleted file mode 100644 index 6685f8f7c..000000000 --- a/src/libfreeswan/ultot.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * convert unsigned long to text - * Copyright (C) 2000 Henry Spencer. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Library General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public - * License for more details. - */ -#include "internal.h" -#include "freeswan.h" - -/* - - ultot - convert unsigned long to text - */ -size_t /* length required for full conversion */ -ultot(n, base, dst, dstlen) -unsigned long n; -int base; -char *dst; /* need not be valid if dstlen is 0 */ -size_t dstlen; -{ - char buf[3*sizeof(unsigned long) + 1]; - char *bufend = buf + sizeof(buf); - size_t len; - char *p; - static char hex[] = "0123456789abcdef"; -# define HEX32 (32/4) - - p = bufend; - *--p = '\0'; - switch (base) { - case 10: - case 'd': - do { - *--p = n%10 + '0'; - n /= 10; - } while (n != 0); - break; - case 16: - case 17: - case 'x': - do { - *--p = hex[n&0xf]; - n >>= 4; - } while (n != 0); - if (base == 17) - while (bufend - p < HEX32 + 1) - *--p = '0'; - if (base == 'x') { - *--p = 'x'; - *--p = '0'; - } - break; - case 8: - case 'o': - do { - *--p = (n&07) + '0'; - n >>= 3; - } while (n != 0); - if (base == 'o') - *--p = '0'; - break; - default: - return 0; - break; - } - - len = bufend - p; - if (dstlen > 0) { - if (len > dstlen) - *(p + dstlen - 1) = '\0'; - strcpy(dst, p); - } - return len; -} diff --git a/src/libhydra/Makefile.in b/src/libhydra/Makefile.in index f452719dd..a10981a94 100644 --- a/src/libhydra/Makefile.in +++ b/src/libhydra/Makefile.in @@ -63,6 +63,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -94,7 +95,7 @@ libhydra_la_DEPENDENCIES = $(am__append_2) $(am__append_4) \ am_libhydra_la_OBJECTS = hydra.lo attributes.lo attribute_manager.lo \ mem_pool.lo kernel_interface.lo kernel_ipsec.lo kernel_net.lo libhydra_la_OBJECTS = $(am_libhydra_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -160,6 +161,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -254,11 +256,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -275,11 +280,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -295,6 +301,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -304,7 +311,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/attributes/attribute_handler.h b/src/libhydra/attributes/attribute_handler.h index d042f47ef..6014ef0fa 100644 --- a/src/libhydra/attributes/attribute_handler.h +++ b/src/libhydra/attributes/attribute_handler.h @@ -22,8 +22,8 @@ #define ATTRIBUTE_HANDLER_H_ #include -#include #include +#include #include "attributes.h" @@ -62,11 +62,11 @@ struct attribute_handler_t { * Enumerate attributes to request from a server. * * @param server server identity to request attributes from - * @param vip virtual IP we are requesting, if any + * @param vips list of virtual IPs (host_t*) we are requesting * @return enumerator (configuration_attribute_type_t, chunk_t) */ enumerator_t* (*create_attribute_enumerator)(attribute_handler_t *this, - identification_t *server, host_t *vip); + identification_t *server, linked_list_t *vips); }; #endif /** ATTRIBUTE_HANDLER_H_ @}*/ diff --git a/src/libhydra/attributes/attribute_manager.c b/src/libhydra/attributes/attribute_manager.c index 95520531e..000d2e082 100644 --- a/src/libhydra/attributes/attribute_manager.c +++ b/src/libhydra/attributes/attribute_manager.c @@ -51,17 +51,17 @@ struct private_attribute_manager_t { * Data to pass to enumerator filters */ typedef struct { - /** attribute group pool */ - char *pool; + /** attribute group pools */ + linked_list_t *pools; /** server/peer identity */ identification_t *id; - /** requesting/assigned virtual IP */ - host_t *vip; + /** requesting/assigned virtual IPs */ + linked_list_t *vips; } enum_data_t; METHOD(attribute_manager_t, acquire_address, host_t*, - private_attribute_manager_t *this, char *pool, identification_t *id, - host_t *requested) + private_attribute_manager_t *this, linked_list_t *pools, + identification_t *id, host_t *requested) { enumerator_t *enumerator; attribute_provider_t *current; @@ -71,7 +71,7 @@ METHOD(attribute_manager_t, acquire_address, host_t*, enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, ¤t)) { - host = current->acquire_address(current, pool, id, requested); + host = current->acquire_address(current, pools, id, requested); if (host) { break; @@ -80,15 +80,11 @@ METHOD(attribute_manager_t, acquire_address, host_t*, enumerator->destroy(enumerator); this->lock->unlock(this->lock); - if (!host) - { - DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool); - } return host; } -METHOD(attribute_manager_t, release_address, void, - private_attribute_manager_t *this, char *pool, host_t *address, +METHOD(attribute_manager_t, release_address, bool, + private_attribute_manager_t *this, linked_list_t *pools, host_t *address, identification_t *id) { enumerator_t *enumerator; @@ -99,7 +95,7 @@ METHOD(attribute_manager_t, release_address, void, enumerator = this->providers->create_enumerator(this->providers); while (enumerator->enumerate(enumerator, ¤t)) { - if (current->release_address(current, pool, address, id)) + if (current->release_address(current, pools, address, id)) { found = TRUE; break; @@ -108,10 +104,7 @@ METHOD(attribute_manager_t, release_address, void, enumerator->destroy(enumerator); this->lock->unlock(this->lock); - if (!found) - { - DBG1(DBG_CFG, "releasing address to pool '%s' failed", pool); - } + return found; } /** @@ -120,19 +113,21 @@ METHOD(attribute_manager_t, release_address, void, static enumerator_t *responder_enum_create(attribute_provider_t *provider, enum_data_t *data) { - return provider->create_attribute_enumerator(provider, data->pool, - data->id, data->vip); + return provider->create_attribute_enumerator(provider, data->pools, + data->id, data->vips); } METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*, - private_attribute_manager_t *this, char *pool, identification_t *id, - host_t *vip) + private_attribute_manager_t *this, linked_list_t *pools, + identification_t *id, linked_list_t *vips) { - enum_data_t *data = malloc_thing(enum_data_t); + enum_data_t *data; - data->pool = pool; - data->id = id; - data->vip = vip; + INIT(data, + .pools = pools, + .id = id, + .vips = vips, + ); this->lock->read_lock(this->lock); return enumerator_create_cleaner( enumerator_create_nested( @@ -238,8 +233,8 @@ typedef struct { enumerator_t *inner; /** server ID we want attributes for */ identification_t *id; - /** virtual IP we are requesting along with attriubutes */ - host_t *vip; + /** virtual IPs we are requesting along with attriubutes */ + linked_list_t *vips; } initiator_enumerator_t; /** @@ -259,7 +254,7 @@ static bool initiator_enumerate(initiator_enumerator_t *this, } DESTROY_IF(this->inner); this->inner = this->handler->create_attribute_enumerator(this->handler, - this->id, this->vip); + this->id, this->vips); } /* inject the handler as additional attribute */ *handler = this->handler; @@ -278,20 +273,22 @@ static void initiator_destroy(initiator_enumerator_t *this) } METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*, - private_attribute_manager_t *this, identification_t *id, host_t *vip) + private_attribute_manager_t *this, identification_t *id, linked_list_t *vips) { - initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t); + initiator_enumerator_t *enumerator; this->lock->read_lock(this->lock); - enumerator->public.enumerate = (void*)initiator_enumerate; - enumerator->public.destroy = (void*)initiator_destroy; - enumerator->this = this; - enumerator->id = id; - enumerator->vip = vip; - enumerator->outer = this->handlers->create_enumerator(this->handlers); - enumerator->inner = NULL; - enumerator->handler = NULL; + INIT(enumerator, + .public = { + .enumerate = (void*)initiator_enumerate, + .destroy = (void*)initiator_destroy, + }, + .this = this, + .id = id, + .vips = vips, + .outer = this->handlers->create_enumerator(this->handlers), + ); return &enumerator->public; } diff --git a/src/libhydra/attributes/attribute_manager.h b/src/libhydra/attributes/attribute_manager.h index 56afef7c6..99f41772c 100644 --- a/src/libhydra/attributes/attribute_manager.h +++ b/src/libhydra/attributes/attribute_manager.h @@ -39,35 +39,38 @@ struct attribute_manager_t { /** * Acquire a virtual IP address to assign to a peer. * - * @param pool pool name to acquire address from + * @param pools list of pool names (char*) to acquire from * @param id peer identity to get address forua * @param requested IP in configuration request * @return allocated address, NULL to serve none */ host_t* (*acquire_address)(attribute_manager_t *this, - char *pool, identification_t *id, + linked_list_t *pool, identification_t *id, host_t *requested); /** * Release a previously acquired address. * - * @param pool pool name from which the address was acquired + * @param pools list of pool names (char*) to release to * @param address address to release * @param id peer identity to get address for + * @return TRUE if address released to pool */ - void (*release_address)(attribute_manager_t *this, - char *pool, host_t *address, identification_t *id); + bool (*release_address)(attribute_manager_t *this, + linked_list_t *pools, host_t *address, + identification_t *id); /** * Create an enumerator over attributes to hand out to a peer. * - * @param pool pool name to get attributes from + * @param pool list of pools names (char*) to query attributes from * @param id peer identity to hand out attributes to - * @param vip virtual IP to assign to peer, if any + * @param vip list of virtual IPs (host_t*) to assign to peer * @return enumerator (configuration_attribute_type_t, chunk_t) */ enumerator_t* (*create_responder_enumerator)(attribute_manager_t *this, - char *pool, identification_t *id, host_t *vip); + linked_list_t *pool, identification_t *id, + linked_list_t *vips); /** * Register an attribute provider to the manager. @@ -114,11 +117,11 @@ struct attribute_manager_t { * Create an enumerator over attributes to request from server. * * @param id server identity to hand out attributes to - * @param vip virtual IP going to request, if any + * @param vip list of virtual IPs (host_t*) going to request * @return enumerator (attribute_handler_t, ca_type_t, chunk_t) */ enumerator_t* (*create_initiator_enumerator)(attribute_manager_t *this, - identification_t *id, host_t *vip); + identification_t *id, linked_list_t *vips); /** * Register an attribute handler to the manager. diff --git a/src/libhydra/attributes/attribute_provider.h b/src/libhydra/attributes/attribute_provider.h index e4b4e13f3..e5e556fc4 100644 --- a/src/libhydra/attributes/attribute_provider.h +++ b/src/libhydra/attributes/attribute_provider.h @@ -23,6 +23,7 @@ #include #include +#include typedef struct attribute_provider_t attribute_provider_t; @@ -34,35 +35,37 @@ struct attribute_provider_t { /** * Acquire a virtual IP address to assign to a peer. * - * @param pool name of the pool to acquire address from + * @param pools list of pool names (char*) to acquire from * @param id peer ID * @param requested IP in configuration request * @return allocated address, NULL to serve none */ host_t* (*acquire_address)(attribute_provider_t *this, - char *pool, identification_t *id, + linked_list_t *pools, identification_t *id, host_t *requested); /** * Release a previously acquired address. * - * @param pool name of the pool this address was acquired from + * @param pools list of pool names (char*) to release to * @param address address to release * @param id peer ID * @return TRUE if the address has been released by the provider */ bool (*release_address)(attribute_provider_t *this, - char *pool, host_t *address, identification_t *id); + linked_list_t *pools, host_t *address, + identification_t *id); /** * Create an enumerator over attributes to hand out to a peer. * - * @param pool pool name to get attributes from + * @param pool list of pools names (char*) to query attributes from * @param id peer ID - * @param vip virtual IP to assign to peer, if any + * @param vip list of virtual IPs (host_t*) to assign to peer * @return enumerator (configuration_attribute_type_t, chunk_t) */ enumerator_t* (*create_attribute_enumerator)(attribute_provider_t *this, - char *pool, identification_t *id, host_t *vip); + linked_list_t *pools, identification_t *id, + linked_list_t *vips); }; #endif /** ATTRIBUTE_PROVIDER_H_ @}*/ diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c index 8af97dc78..1e150c794 100644 --- a/src/libhydra/attributes/mem_pool.c +++ b/src/libhydra/attributes/mem_pool.c @@ -162,6 +162,12 @@ METHOD(mem_pool_t, get_name, const char*, return this->name; } +METHOD(mem_pool_t, get_base, host_t*, + private_mem_pool_t *this) +{ + return this->base; +} + METHOD(mem_pool_t, get_size, u_int, private_mem_pool_t *this) { @@ -206,66 +212,68 @@ METHOD(mem_pool_t, get_offline, u_int, return count; } -METHOD(mem_pool_t, acquire_address, host_t*, - private_mem_pool_t *this, identification_t *id, host_t *requested) +/** + * Get an existing lease for id + */ +static int get_existing(private_mem_pool_t *this, identification_t *id, + host_t *requested) { - uintptr_t offset = 0, current; enumerator_t *enumerator; - entry_t *entry, *old; + uintptr_t current; + entry_t *entry; + int offset = 0; - /* if the pool is empty (e.g. in the %config case) we simply return the - * requested address */ - if (this->size == 0) + entry = this->leases->get(this->leases, id); + if (!entry) { - return requested->clone(requested); + return 0; } - if (!requested->is_anyaddr(requested) && - requested->get_family(requested) != - this->base->get_family(this->base)) + /* check for a valid offline lease, refresh */ + enumerator = entry->offline->create_enumerator(entry->offline); + if (enumerator->enumerate(enumerator, ¤t)) { - DBG1(DBG_CFG, "IP pool address family mismatch"); - return NULL; + entry->offline->remove_at(entry->offline, enumerator); + entry->online->insert_last(entry->online, (void*)current); + offset = current; + } + enumerator->destroy(enumerator); + if (offset) + { + DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id); + return offset; } - this->mutex->lock(this->mutex); - while (TRUE) + /* check for a valid online lease to reassign */ + enumerator = entry->online->create_enumerator(entry->online); + while (enumerator->enumerate(enumerator, ¤t)) { - entry = this->leases->get(this->leases, id); - if (entry) + if (current == host2offset(this, requested)) { - /* check for a valid offline lease, refresh */ - enumerator = entry->offline->create_enumerator(entry->offline); - if (enumerator->enumerate(enumerator, ¤t)) - { - entry->offline->remove_at(entry->offline, enumerator); - entry->online->insert_last(entry->online, (void*)current); - offset = current; - } - enumerator->destroy(enumerator); - if (offset) - { - DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id); - break; - } - /* check for a valid online lease to reassign */ - enumerator = entry->online->create_enumerator(entry->online); - while (enumerator->enumerate(enumerator, ¤t)) - { - if (current == host2offset(this, requested)) - { - offset = current; - break; - } - } - enumerator->destroy(enumerator); - if (offset) - { - DBG1(DBG_CFG, "reassigning online lease to '%Y'", id); - break; - } + offset = current; + break; } - else + } + enumerator->destroy(enumerator); + if (offset) + { + DBG1(DBG_CFG, "reassigning online lease to '%Y'", id); + } + return offset; +} + +/** + * Get a new lease for id + */ +static int get_new(private_mem_pool_t *this, identification_t *id) +{ + entry_t *entry; + uintptr_t offset = 0; + + if (this->unused < this->size) + { + entry = this->leases->get(this->leases, id); + if (!entry) { INIT(entry, .id = id->clone(id), @@ -274,31 +282,88 @@ METHOD(mem_pool_t, acquire_address, host_t*, ); this->leases->put(this->leases, entry->id, entry); } - if (this->unused < this->size) + /* assigning offset, starting by 1 */ + offset = ++this->unused; + entry->online->insert_last(entry->online, (void*)offset); + DBG1(DBG_CFG, "assigning new lease to '%Y'", id); + } + return offset; +} + +/** + * Get a reassigned lease for id in case the pool is full + */ +static int get_reassigned(private_mem_pool_t *this, identification_t *id) +{ + enumerator_t *enumerator; + entry_t *entry; + uintptr_t current, offset = 0; + + enumerator = this->leases->create_enumerator(this->leases); + while (enumerator->enumerate(enumerator, NULL, &entry)) + { + if (entry->offline->remove_first(entry->offline, + (void**)¤t) == SUCCESS) { - /* assigning offset, starting by 1 */ - offset = ++this->unused; - entry->online->insert_last(entry->online, (void*)offset); - DBG1(DBG_CFG, "assigning new lease to '%Y'", id); + offset = current; + DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'" + " to '%Y'", entry->id, id); break; } + } + enumerator->destroy(enumerator); - /* no more addresses, replace the first found offline lease */ - enumerator = this->leases->create_enumerator(this->leases); - while (enumerator->enumerate(enumerator, NULL, &old)) - { - if (old->offline->remove_first(old->offline, - (void**)¤t) == SUCCESS) + if (offset) + { + INIT(entry, + .id = id->clone(id), + .online = linked_list_create(), + .offline = linked_list_create(), + ); + entry->online->insert_last(entry->online, (void*)offset); + this->leases->put(this->leases, entry->id, entry); + } + return offset; +} + +METHOD(mem_pool_t, acquire_address, host_t*, + private_mem_pool_t *this, identification_t *id, host_t *requested, + mem_pool_op_t operation) +{ + int offset = 0; + + /* if the pool is empty (e.g. in the %config case) we simply return the + * requested address */ + if (this->size == 0) + { + return requested->clone(requested); + } + + if (requested->get_family(requested) != + this->base->get_family(this->base)) + { + return NULL; + } + + this->mutex->lock(this->mutex); + switch (operation) + { + case MEM_POOL_EXISTING: + offset = get_existing(this, id, requested); + break; + case MEM_POOL_NEW: + offset = get_new(this, id); + break; + case MEM_POOL_REASSIGN: + offset = get_reassigned(this, id); + if (!offset) { - offset = current; - entry->online->insert_last(entry->online, (void*)offset); - DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'" - " to '%Y'", old->id, id); - break; + DBG1(DBG_CFG, "pool '%s' is full, unable to assign address", + this->name); } - } - enumerator->destroy(enumerator); - break; + break; + default: + break; } this->mutex->unlock(this->mutex); @@ -306,11 +371,6 @@ METHOD(mem_pool_t, acquire_address, host_t*, { return offset2host(this, offset); } - else - { - DBG1(DBG_CFG, "pool '%s' is full, unable to assign address", - this->name); - } return NULL; } @@ -463,6 +523,7 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) INIT(this, .public = { .get_name = _get_name, + .get_base = _get_base, .get_size = _get_size, .get_online = _get_online, .get_offline = _get_offline, @@ -480,6 +541,7 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) if (base) { addr_bits = base->get_family(base) == AF_INET ? 32 : 128; + bits = max(0, min(bits, base->get_family(base) == AF_INET ? 32 : 128)); /* net bits -> host bits */ bits = addr_bits - bits; if (bits > POOL_LIMIT) @@ -493,7 +555,7 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits) if (this->size > 2) { /* do not use first and last addresses of a block */ this->unused++; - this->size--; + this->size -= 2; } this->base = base->clone(base); } diff --git a/src/libhydra/attributes/mem_pool.h b/src/libhydra/attributes/mem_pool.h index bb963de93..fa4e6485c 100644 --- a/src/libhydra/attributes/mem_pool.h +++ b/src/libhydra/attributes/mem_pool.h @@ -22,10 +22,23 @@ #define MEM_POOL_H typedef struct mem_pool_t mem_pool_t; +typedef enum mem_pool_op_t mem_pool_op_t; #include #include +/** + * In-memory IP pool acquire operation. + */ +enum mem_pool_op_t { + /** Check for an exsiting lease */ + MEM_POOL_EXISTING, + /** Get a new lease */ + MEM_POOL_NEW, + /** Replace an existing offline lease of another ID */ + MEM_POOL_REASSIGN, +}; + /** * An in-memory IP address pool. */ @@ -38,6 +51,13 @@ struct mem_pool_t { */ const char* (*get_name)(mem_pool_t *this); + /** + * Get the base (first) address of this pool. + * + * @return base address, internal host + */ + host_t* (*get_base)(mem_pool_t *this); + /** * Get the size (i.e. number of addresses) of this pool. * @@ -62,12 +82,18 @@ struct mem_pool_t { /** * Acquire an address for the given id from this pool. * + * This call is usually invoked several times: The first time to find an + * existing lease (MEM_POOL_EXISTING), if none found a second time to + * acquire a new lease (MEM_POOL_NEW), and if the pool is full once again + * to assign an existing offline lease (MEM_POOL_REASSIGN). + * * @param id the id to acquire an address for * @param requested acquire this address, if possible + * @param existing TRUE to look for an existing lease, FALSE for a new one * @return the acquired address */ host_t* (*acquire_address)(mem_pool_t *this, identification_t *id, - host_t *requested); + host_t *requested, mem_pool_op_t operation); /** * Release a previously acquired address. diff --git a/src/libhydra/hydra.c b/src/libhydra/hydra.c index f180e36bb..7d6256598 100644 --- a/src/libhydra/hydra.c +++ b/src/libhydra/hydra.c @@ -58,12 +58,13 @@ bool libhydra_init(const char *daemon) INIT(this, .public = { .attributes = attribute_manager_create(), - .kernel_interface = kernel_interface_create(), .daemon = strdup(daemon ?: "libhydra"), }, ); hydra = &this->public; + this->public.kernel_interface = kernel_interface_create(); + if (lib->integrity && !lib->integrity->check(lib->integrity, "libhydra", libhydra_init)) { diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c index 573557506..5320ee2e9 100644 --- a/src/libhydra/kernel/kernel_interface.c +++ b/src/libhydra/kernel/kernel_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG @@ -15,14 +15,65 @@ * for more details. */ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + #include "kernel_interface.h" +#include #include #include #include typedef struct private_kernel_interface_t private_kernel_interface_t; +typedef struct kernel_algorithm_t kernel_algorithm_t; + +/** + * Mapping of IKE algorithms to kernel-specific algorithm identifiers + */ +struct kernel_algorithm_t { + + /** + * Transform type of the algorithm + */ + transform_type_t type; + + /** + * Identifier specified in IKE + */ + u_int16_t ike; + + /** + * Identifier as defined in pfkeyv2.h + */ + u_int16_t kernel; + + /** + * Name of the algorithm in linux crypto API + */ + char *name; +}; + /** * Private data of a kernel_interface_t object. */ @@ -62,6 +113,28 @@ struct private_kernel_interface_t { * list of registered listeners */ linked_list_t *listeners; + + /** + * mutex for algorithm mappings + */ + mutex_t *mutex_algs; + + /** + * List of algorithm mappings (kernel_algorithm_t*) + */ + linked_list_t *algorithms; + + /** + * List of interface names to include or exclude (char*), NULL if interfaces + * are not filtered + */ + linked_list_t *ifaces_filter; + + /** + * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider + * only those listed there + */ + bool ifaces_exclude; }; METHOD(kernel_interface_t, get_spi, status_t, @@ -209,35 +282,33 @@ METHOD(kernel_interface_t, get_source_addr, host_t*, } METHOD(kernel_interface_t, get_nexthop, host_t*, - private_kernel_interface_t *this, host_t *dest) + private_kernel_interface_t *this, host_t *dest, host_t *src) { if (!this->net) { return NULL; } - return this->net->get_nexthop(this->net, dest); + return this->net->get_nexthop(this->net, dest, src); } -METHOD(kernel_interface_t, get_interface, char*, - private_kernel_interface_t *this, host_t *host) +METHOD(kernel_interface_t, get_interface, bool, + private_kernel_interface_t *this, host_t *host, char **name) { if (!this->net) { return NULL; } - return this->net->get_interface(this->net, host); + return this->net->get_interface(this->net, host, name); } METHOD(kernel_interface_t, create_address_enumerator, enumerator_t*, - private_kernel_interface_t *this, bool include_down_ifaces, - bool include_virtual_ips) + private_kernel_interface_t *this, kernel_address_type_t which) { if (!this->net) { return enumerator_create_empty(); } - return this->net->create_address_enumerator(this->net, include_down_ifaces, - include_virtual_ips); + return this->net->create_address_enumerator(this->net, which); } METHOD(kernel_interface_t, add_ip, status_t, @@ -294,6 +365,36 @@ METHOD(kernel_interface_t, bypass_socket, bool, return this->ipsec->bypass_socket(this->ipsec, fd, family); } +METHOD(kernel_interface_t, enable_udp_decap, bool, + private_kernel_interface_t *this, int fd, int family, u_int16_t port) +{ + if (!this->ipsec) + { + return FALSE; + } + return this->ipsec->enable_udp_decap(this->ipsec, fd, family, port); +} + +METHOD(kernel_interface_t, is_interface_usable, bool, + private_kernel_interface_t *this, const char *iface) +{ + status_t expected; + + if (!this->ifaces_filter) + { + return TRUE; + } + expected = this->ifaces_exclude ? NOT_FOUND : SUCCESS; + return this->ifaces_filter->find_first(this->ifaces_filter, (void*)streq, + NULL, iface) == expected; +} + +METHOD(kernel_interface_t, all_interfaces_usable, bool, + private_kernel_interface_t *this) +{ + return this->ifaces_filter == NULL; +} + METHOD(kernel_interface_t, get_address_by_ts, status_t, private_kernel_interface_t *this, traffic_selector_t *ts, host_t **ip) { @@ -326,7 +427,7 @@ METHOD(kernel_interface_t, get_address_by_ts, status_t, } host->destroy(host); - addrs = create_address_enumerator(this, TRUE, TRUE); + addrs = create_address_enumerator(this, ADDR_TYPE_ALL); while (addrs->enumerate(addrs, (void**)&host)) { if (ts->includes(ts, host)) @@ -362,7 +463,7 @@ METHOD(kernel_interface_t, add_ipsec_interface, void, METHOD(kernel_interface_t, remove_ipsec_interface, void, private_kernel_interface_t *this, kernel_ipsec_constructor_t constructor) { - if (constructor == this->ipsec_constructor) + if (constructor == this->ipsec_constructor && this->ipsec) { this->ipsec->destroy(this->ipsec); this->ipsec = NULL; @@ -382,7 +483,7 @@ METHOD(kernel_interface_t, add_net_interface, void, METHOD(kernel_interface_t, remove_net_interface, void, private_kernel_interface_t *this, kernel_net_constructor_t constructor) { - if (constructor == this->net_constructor) + if (constructor == this->net_constructor && this->net) { this->net->destroy(this->net); this->net = NULL; @@ -500,13 +601,73 @@ METHOD(kernel_interface_t, roam, void, this->mutex->unlock(this->mutex); } +METHOD(kernel_interface_t, register_algorithm, void, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t kernel_id, char *kernel_name) +{ + kernel_algorithm_t *algorithm; + + INIT(algorithm, + .type = type, + .ike = alg_id, + .kernel = kernel_id, + .name = strdup(kernel_name), + ); + + this->mutex_algs->lock(this->mutex_algs); + this->algorithms->insert_first(this->algorithms, algorithm); + this->mutex_algs->unlock(this->mutex_algs); +} + +METHOD(kernel_interface_t, lookup_algorithm, bool, + private_kernel_interface_t *this, u_int16_t alg_id, transform_type_t type, + u_int16_t *kernel_id, char **kernel_name) +{ + kernel_algorithm_t *algorithm; + enumerator_t *enumerator; + bool found = FALSE; + + this->mutex_algs->lock(this->mutex_algs); + enumerator = this->algorithms->create_enumerator(this->algorithms); + while (enumerator->enumerate(enumerator, &algorithm)) + { + if (algorithm->type == type && algorithm->ike == alg_id) + { + if (kernel_id) + { + *kernel_id = algorithm->kernel; + } + if (kernel_name) + { + *kernel_name = algorithm->name; + } + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + this->mutex_algs->unlock(this->mutex_algs); + return found; +} + METHOD(kernel_interface_t, destroy, void, private_kernel_interface_t *this) { + kernel_algorithm_t *algorithm; + + while (this->algorithms->remove_first(this->algorithms, + (void**)&algorithm) == SUCCESS) + { + free(algorithm->name); + free(algorithm); + } + this->algorithms->destroy(this->algorithms); + this->mutex_algs->destroy(this->mutex_algs); DESTROY_IF(this->ipsec); DESTROY_IF(this->net); - this->mutex->destroy(this->mutex); + DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free); this->listeners->destroy(this->listeners); + this->mutex->destroy(this->mutex); free(this); } @@ -516,6 +677,7 @@ METHOD(kernel_interface_t, destroy, void, kernel_interface_t *kernel_interface_create() { private_kernel_interface_t *this; + char *ifaces; INIT(this, .public = { @@ -539,7 +701,10 @@ kernel_interface_t *kernel_interface_create() .add_route = _add_route, .del_route = _del_route, .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, + .is_interface_usable = _is_interface_usable, + .all_interfaces_usable = _all_interfaces_usable, .get_address_by_ts = _get_address_by_ts, .add_ipsec_interface = _add_ipsec_interface, .remove_ipsec_interface = _remove_ipsec_interface, @@ -548,6 +713,8 @@ kernel_interface_t *kernel_interface_create() .add_listener = _add_listener, .remove_listener = _remove_listener, + .register_algorithm = _register_algorithm, + .lookup_algorithm = _lookup_algorithm, .acquire = _acquire, .expire = _expire, .mapping = _mapping, @@ -557,8 +724,36 @@ kernel_interface_t *kernel_interface_create() }, .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .listeners = linked_list_create(), + .mutex_algs = mutex_create(MUTEX_TYPE_DEFAULT), + .algorithms = linked_list_create(), ); + ifaces = lib->settings->get_str(lib->settings, + "%s.interfaces_use", NULL, hydra->daemon); + if (!ifaces) + { + this->ifaces_exclude = TRUE; + ifaces = lib->settings->get_str(lib->settings, + "%s.interfaces_ignore", NULL, hydra->daemon); + } + if (ifaces) + { + enumerator_t *enumerator; + char *iface; + + enumerator = enumerator_create_token(ifaces, ",", " "); + while (enumerator->enumerate(enumerator, &iface)) + { + if (!this->ifaces_filter) + { + this->ifaces_filter = linked_list_create(); + } + this->ifaces_filter->insert_last(this->ifaces_filter, + strdup(iface)); + } + enumerator->destroy(enumerator); + } + return &this->public; } diff --git a/src/libhydra/kernel/kernel_interface.h b/src/libhydra/kernel/kernel_interface.h index 991cfafd0..88d4a5bce 100644 --- a/src/libhydra/kernel/kernel_interface.h +++ b/src/libhydra/kernel/kernel_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -16,6 +16,28 @@ * for more details. */ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + /** * @defgroup kernel_interface kernel_interface * @{ @ingroup hkernel @@ -260,7 +282,7 @@ struct kernel_interface_t { * Does a route lookup to get the source address used to reach dest. * The returned host is allocated and must be destroyed. * An optional src address can be used to check if a route is available - * for given source to dest. + * for the given source to dest. * * @param dest target destination address * @param src source address to check, or NULL @@ -274,19 +296,23 @@ struct kernel_interface_t { * * Does a route lookup to get the next hop used to reach dest. * The returned host is allocated and must be destroyed. + * An optional src address can be used to check if a route is available + * for the given source to dest. * * @param dest target destination address * @return next hop address, NULL if unreachable */ - host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest); + host_t* (*get_nexthop)(kernel_interface_t *this, host_t *dest, host_t *src); /** - * Get the interface name of a local address. + * Get the interface name of a local address. Interfaces that are down or + * ignored by config are not considered. * * @param host address to get interface name from - * @return allocated interface name, or NULL if not found + * @param name allocated interface name (optional) + * @return TRUE if interface found and usable */ - char* (*get_interface) (kernel_interface_t *this, host_t *host); + bool (*get_interface)(kernel_interface_t *this, host_t *host, char **name); /** * Creates an enumerator over all local addresses. @@ -295,12 +321,11 @@ struct kernel_interface_t { * enumerator gets destroyed. * The hosts are read-only, do not modify of free. * - * @param include_down_ifaces TRUE to enumerate addresses from down interfaces - * @param include_virtual_ips TRUE to enumerate virtual ip addresses - * @return enumerator over host_t's + * @param which a combination of address types to enumerate + * @return enumerator over host_t's */ enumerator_t *(*create_address_enumerator) (kernel_interface_t *this, - bool include_down_ifaces, bool include_virtual_ips); + kernel_address_type_t which); /** * Add a virtual IP to an interface. @@ -361,20 +386,48 @@ struct kernel_interface_t { * * @param fd socket file descriptor to setup policy for * @param family protocol family of the socket - * @return TRUE of policy set up successfully + * @return TRUE if policy set up successfully */ bool (*bypass_socket)(kernel_interface_t *this, int fd, int family); + /** + * Enable decapsulation of ESP-in-UDP packets for the given port/socket. + * + * @param fd socket file descriptor + * @param family protocol family of the socket + * @param port the UDP port + * @return TRUE if UDP decapsulation was enabled successfully + */ + bool (*enable_udp_decap)(kernel_interface_t *this, int fd, int family, + u_int16_t port); + + /** * manager methods */ /** - * Tries to find an ip address of a local interface that is included in the + * Verifies that the given interface is usable and not excluded by + * configuration. + * + * @param iface interface name + * @return TRUE if usable + */ + bool (*is_interface_usable)(kernel_interface_t *this, const char *iface); + + /** + * Check if interfaces are excluded by config. + * + * @return TRUE if no interfaces are exclued by config + */ + bool (*all_interfaces_usable)(kernel_interface_t *this); + + /** + * Tries to find an IP address of a local interface that is included in the * supplied traffic selector. * * @param ts traffic selector - * @param ip returned ip (has to be destroyed) + * @param ip returned IP address (has to be destroyed) * @return SUCCESS if address found */ status_t (*get_address_by_ts)(kernel_interface_t *this, @@ -480,6 +533,32 @@ struct kernel_interface_t { */ void (*roam)(kernel_interface_t *this, bool address); + /** + * Register a new algorithm with the kernel interface. + * + * @param alg_id the IKE id of the algorithm + * @param type the transform type of the algorithm + * @param kernel_id the kernel id of the algorithm + * @param kernel_name the kernel name of the algorithm + */ + void (*register_algorithm)(kernel_interface_t *this, u_int16_t alg_id, + transform_type_t type, u_int16_t kernel_id, + char *kernel_name); + + /** + * Return the kernel-specific id and/or name for an algorithms depending on + * the arguments specified. + * + * @param alg_id the IKE id of the algorithm + * @param type the transform type of the algorithm + * @param kernel_id the kernel id of the algorithm (optional) + * @param kernel_name the kernel name of the algorithm (optional) + * @return TRUE if algorithm was found + */ + bool (*lookup_algorithm)(kernel_interface_t *this, u_int16_t alg_id, + transform_type_t type, u_int16_t *kernel_id, + char **kernel_name); + /** * Destroys a kernel_interface_manager_t object. */ diff --git a/src/libhydra/kernel/kernel_ipsec.c b/src/libhydra/kernel/kernel_ipsec.c index 9b38297cc..1a32ab4e7 100644 --- a/src/libhydra/kernel/kernel_ipsec.c +++ b/src/libhydra/kernel/kernel_ipsec.c @@ -17,28 +17,6 @@ #include -ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_DROP, - "TRANSPORT", - "TUNNEL", - "BEET", - "PASS", - "DROP" -); - -ENUM(policy_dir_names, POLICY_IN, POLICY_FWD, - "in", - "out", - "fwd" -); - -ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH, - "IPCOMP_NONE", - "IPCOMP_OUI", - "IPCOMP_DEFLATE", - "IPCOMP_LZS", - "IPCOMP_LZJH" -); - /** * See header */ diff --git a/src/libhydra/kernel/kernel_ipsec.h b/src/libhydra/kernel/kernel_ipsec.h index ddb63283c..ee0ade2aa 100644 --- a/src/libhydra/kernel/kernel_ipsec.h +++ b/src/libhydra/kernel/kernel_ipsec.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter @@ -24,151 +24,13 @@ #ifndef KERNEL_IPSEC_H_ #define KERNEL_IPSEC_H_ -typedef enum ipsec_mode_t ipsec_mode_t; -typedef enum policy_dir_t policy_dir_t; -typedef enum policy_type_t policy_type_t; -typedef enum policy_priority_t policy_priority_t; -typedef enum ipcomp_transform_t ipcomp_transform_t; typedef struct kernel_ipsec_t kernel_ipsec_t; -typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t; -typedef struct lifetime_cfg_t lifetime_cfg_t; -typedef struct mark_t mark_t; #include -#include +#include #include #include -/** - * Mode of an IPsec SA. - */ -enum ipsec_mode_t { - /** transport mode, no inner address */ - MODE_TRANSPORT = 1, - /** tunnel mode, inner and outer addresses */ - MODE_TUNNEL, - /** BEET mode, tunnel mode but fixed, bound inner addresses */ - MODE_BEET, - /** passthrough policy for traffic without an IPsec SA */ - MODE_PASS, - /** drop policy discarding traffic */ - MODE_DROP -}; - -/** - * enum names for ipsec_mode_t. - */ -extern enum_name_t *ipsec_mode_names; - -/** - * Direction of a policy. These are equal to those - * defined in xfrm.h, but we want to stay implementation - * neutral here. - */ -enum policy_dir_t { - /** Policy for inbound traffic */ - POLICY_IN = 0, - /** Policy for outbound traffic */ - POLICY_OUT = 1, - /** Policy for forwarded traffic */ - POLICY_FWD = 2, -}; - -/** - * enum names for policy_dir_t. - */ -extern enum_name_t *policy_dir_names; - -/** - * Type of a policy. - */ -enum policy_type_t { - /** Normal IPsec policy */ - POLICY_IPSEC = 1, - /** Passthrough policy (traffic is ignored by IPsec) */ - POLICY_PASS, - /** Drop policy (traffic is discarded) */ - POLICY_DROP, -}; - -/** - * High-level priority of a policy. - */ -enum policy_priority_t { - /** Default priority */ - POLICY_PRIORITY_DEFAULT, - /** Priority for trap policies */ - POLICY_PRIORITY_ROUTED, - /** Priority for fallback drop policies */ - POLICY_PRIORITY_FALLBACK, -}; - -/** - * IPComp transform IDs, as in RFC 4306 - */ -enum ipcomp_transform_t { - IPCOMP_NONE = 0, - IPCOMP_OUI = 1, - IPCOMP_DEFLATE = 2, - IPCOMP_LZS = 3, - IPCOMP_LZJH = 4, -}; - -/** - * enum strings for ipcomp_transform_t. - */ -extern enum_name_t *ipcomp_transform_names; - -/** - * This struct contains details about IPsec SA(s) tied to a policy. - */ -struct ipsec_sa_cfg_t { - /** mode of SA (tunnel, transport) */ - ipsec_mode_t mode; - /** unique ID */ - u_int32_t reqid; - /** details about ESP/AH */ - struct { - /** TRUE if this protocol is used */ - bool use; - /** SPI for ESP/AH */ - u_int32_t spi; - } esp, ah; - /** details about IPComp */ - struct { - /** the IPComp transform used */ - u_int16_t transform; - /** CPI for IPComp */ - u_int16_t cpi; - } ipcomp; -}; - -/** - * A lifetime_cfg_t defines the lifetime limits of an SA. - * - * Set any of these values to 0 to ignore. - */ -struct lifetime_cfg_t { - struct { - /** Limit before the SA gets invalid. */ - u_int64_t life; - /** Limit before the SA gets rekeyed. */ - u_int64_t rekey; - /** The range of a random value subtracted from rekey. */ - u_int64_t jitter; - } time, bytes, packets; -}; - -/** - * A mark_t defines an optional mark in an IPsec SA. - */ -struct mark_t { - /** Mark value */ - u_int32_t value; - /** Mark mask */ - u_int32_t mask; -}; - /** * Interface to the ipsec subsystem of the kernel. * @@ -395,6 +257,17 @@ struct kernel_ipsec_t { */ bool (*bypass_socket)(kernel_ipsec_t *this, int fd, int family); + /** + * Enable decapsulation of ESP-in-UDP packets for the given port/socket. + * + * @param fd socket file descriptor + * @param family protocol family of the socket + * @param port the UDP port + * @return TRUE if UDP decapsulation was enabled successfully + */ + bool (*enable_udp_decap)(kernel_ipsec_t *this, int fd, int family, + u_int16_t port); + /** * Destroy the implementation. */ diff --git a/src/libhydra/kernel/kernel_net.h b/src/libhydra/kernel/kernel_net.h index a89e76804..10350d644 100644 --- a/src/libhydra/kernel/kernel_net.h +++ b/src/libhydra/kernel/kernel_net.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2007 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -23,11 +23,30 @@ #define KERNEL_NET_H_ typedef struct kernel_net_t kernel_net_t; +typedef enum kernel_address_type_t kernel_address_type_t; #include #include #include +/** + * Type of addresses (e.g. when enumerating them) + */ +enum kernel_address_type_t { + /** normal addresses (on regular, up, non-ignored) interfaces */ + ADDR_TYPE_REGULAR = 0, + /** addresses on down interfaces */ + ADDR_TYPE_DOWN = (1 << 0), + /** addresses on ignored interfaces */ + ADDR_TYPE_IGNORED = (1 << 1), + /** addresses on loopback interfaces */ + ADDR_TYPE_LOOPBACK = (1 << 2), + /** virtual IP addresses */ + ADDR_TYPE_VIRTUAL = (1 << 3), + /** to enumerate all available addresses */ + ADDR_TYPE_ALL = (1 << 4) - 1, +}; + /** * Interface to the network subsystem of the kernel. * @@ -42,7 +61,7 @@ struct kernel_net_t { * Does a route lookup to get the source address used to reach dest. * The returned host is allocated and must be destroyed. * An optional src address can be used to check if a route is available - * for given source to dest. + * for the given source to dest. * * @param dest target destination address * @param src source address to check, or NULL @@ -55,19 +74,24 @@ struct kernel_net_t { * * Does a route lookup to get the next hop used to reach dest. * The returned host is allocated and must be destroyed. + * An optional src address can be used to check if a route is available + * for the given source to dest. * * @param dest target destination address + * @param src source address to check, or NULL * @return next hop address, NULL if unreachable */ - host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest); + host_t* (*get_nexthop)(kernel_net_t *this, host_t *dest, host_t *src); /** - * Get the interface name of a local address. + * Get the interface name of a local address. Interfaces that are down or + * ignored by config are not considered. * * @param host address to get interface name from - * @return allocated interface name, or NULL if not found + * @param name allocated interface name (optional) + * @return TRUE if interface found and usable */ - char* (*get_interface) (kernel_net_t *this, host_t *host); + bool (*get_interface) (kernel_net_t *this, host_t *host, char **name); /** * Creates an enumerator over all local addresses. @@ -76,12 +100,11 @@ struct kernel_net_t { * enumerator gets destroyed. * The hosts are read-only, do not modify of free. * - * @param include_down_ifaces TRUE to enumerate addresses from down interfaces - * @param include_virtual_ips TRUE to enumerate virtual ip addresses - * @return enumerator over host_t's + * @param which a combination of address types to enumerate + * @return enumerator over host_t's */ enumerator_t *(*create_address_enumerator) (kernel_net_t *this, - bool include_down_ifaces, bool include_virtual_ips); + kernel_address_type_t which); /** * Add a virtual IP to an interface. diff --git a/src/libhydra/plugins/attr/Makefile.in b/src/libhydra/plugins/attr/Makefile.in index 1ceb93ef3..831adf9d6 100644 --- a/src/libhydra/plugins/attr/Makefile.in +++ b/src/libhydra/plugins/attr/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_attr_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_attr_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_attr_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_attr_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/attr/attr_provider.c b/src/libhydra/plugins/attr/attr_provider.c index 44242c259..c1c3cd895 100644 --- a/src/libhydra/plugins/attr/attr_provider.c +++ b/src/libhydra/plugins/attr/attr_provider.c @@ -77,10 +77,10 @@ static bool attr_enum_filter(void *null, attribute_entry_t **in, } METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, - private_attr_provider_t *this, char *pool, - identification_t *id, host_t *vip) + private_attr_provider_t *this, linked_list_t *pools, + identification_t *id, linked_list_t *vips) { - if (vip) + if (vips->get_count(vips)) { this->lock->read_lock(this->lock); return enumerator_create_filter( @@ -145,18 +145,22 @@ static void add_legacy_entry(private_attr_provider_t *this, char *key, int nr, /** * Key to attribute type mappings, for v4 and v6 attributes */ -static struct { +typedef struct { char *name; configuration_attribute_type_t v4; configuration_attribute_type_t v6; -} keys[] = { - {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS}, - {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS}, - {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS}, - {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP}, - {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK}, - {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER}, - {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET}, +} attribute_type_key_t; + +static attribute_type_key_t keys[] = { + {"address", INTERNAL_IP4_ADDRESS, INTERNAL_IP6_ADDRESS}, + {"dns", INTERNAL_IP4_DNS, INTERNAL_IP6_DNS}, + {"nbns", INTERNAL_IP4_NBNS, INTERNAL_IP6_NBNS}, + {"dhcp", INTERNAL_IP4_DHCP, INTERNAL_IP6_DHCP}, + {"netmask", INTERNAL_IP4_NETMASK, INTERNAL_IP6_NETMASK}, + {"server", INTERNAL_IP4_SERVER, INTERNAL_IP6_SERVER}, + {"subnet", INTERNAL_IP4_SUBNET, INTERNAL_IP6_SUBNET}, + {"split-include", UNITY_SPLIT_INCLUDE, UNITY_SPLIT_INCLUDE}, + {"split-exclude", UNITY_LOCAL_LAN, UNITY_LOCAL_LAN}, }; /** @@ -179,12 +183,29 @@ static void load_entries(private_attr_provider_t *this) while (enumerator->enumerate(enumerator, &key, &value)) { configuration_attribute_type_t type; + attribute_type_key_t *mapped = NULL; attribute_entry_t *entry; host_t *host; char *pos; - int i, mask = -1; + int i, mask = -1, family; type = atoi(key); + if (!type) + { + for (i = 0; i < countof(keys); i++) + { + if (streq(key, keys[i].name)) + { + mapped = &keys[i]; + break; + } + } + if (!mapped) + { + DBG1(DBG_CFG, "mapping attribute type %s failed", key); + continue; + } + } tokens = enumerator_create_token(value, ",", " "); while (tokens->enumerate(tokens, &token)) { @@ -200,37 +221,16 @@ static void load_entries(private_attr_provider_t *this) DBG1(DBG_CFG, "invalid host in key %s: %s", key, token); continue; } - if (!type) - { - for (i = 0; i < countof(keys); i++) - { - if (streq(key, keys[i].name)) - { - if (host->get_family(host) == AF_INET) - { - type = keys[i].v4; - } - else - { - type = keys[i].v6; - } - } - } - if (!type) - { - DBG1(DBG_CFG, "mapping attribute type %s failed", key); - break; - } - } + family = host->get_family(host); entry = malloc_thing(attribute_entry_t); - entry->type = type; + entry->type = type ?: (family == AF_INET ? mapped->v4 : mapped->v6); if (mask == -1) { entry->value = chunk_clone(host->get_address(host)); } else { - if (host->get_family(host) == AF_INET) + if (family == AF_INET) { /* IPv4 attributes contain a subnet mask */ u_int32_t netmask; diff --git a/src/libhydra/plugins/attr_sql/Makefile.in b/src/libhydra/plugins/attr_sql/Makefile.in index 4fe577f3b..71810ae5e 100644 --- a/src/libhydra/plugins/attr_sql/Makefile.in +++ b/src/libhydra/plugins/attr_sql/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -95,7 +96,7 @@ pool_OBJECTS = $(am_pool_OBJECTS) pool_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libhydra/libhydra.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -121,6 +122,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -215,11 +217,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -236,11 +241,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -256,6 +262,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -265,7 +272,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/attr_sql/pool_attributes.c b/src/libhydra/plugins/attr_sql/pool_attributes.c index 5c7397476..d3fc06eeb 100644 --- a/src/libhydra/plugins/attr_sql/pool_attributes.c +++ b/src/libhydra/plugins/attr_sql/pool_attributes.c @@ -492,7 +492,7 @@ void del_attr(char *name, char *pool, char *identity, { fprintf(stderr, "deleting %s attribute (%N) with value '%.*s'%s failed.\n", name, configuration_attribute_type_names, type, - blob_db.len, blob_db.ptr, id_pool_str); + (int)blob_db.len, blob_db.ptr, id_pool_str); } else @@ -514,7 +514,7 @@ void del_attr(char *name, char *pool, char *identity, { printf("deleted %s attribute (%N) with value '%.*s'%s.\n", name, configuration_attribute_type_names, type, - blob_db.len, blob_db.ptr, id_pool_str); + (int)blob_db.len, blob_db.ptr, id_pool_str); } else { @@ -555,7 +555,7 @@ void del_attr(char *name, char *pool, char *identity, fprintf(stderr, "the %s attribute (%N) with value '%.*s'%s " "was not found.\n", name, configuration_attribute_type_names, type, - blob.len, blob.ptr, id_pool_str); + (int)blob.len, blob.ptr, id_pool_str); } } } diff --git a/src/libhydra/plugins/attr_sql/sql_attribute.c b/src/libhydra/plugins/attr_sql/sql_attribute.c index 714bbcd72..a7d90e728 100644 --- a/src/libhydra/plugins/attr_sql/sql_attribute.c +++ b/src/libhydra/plugins/attr_sql/sql_attribute.c @@ -233,54 +233,37 @@ static host_t* get_lease(private_sql_attribute_t *this, char *name, } METHOD(attribute_provider_t, acquire_address, host_t*, - private_sql_attribute_t *this, char *names, identification_t *id, + private_sql_attribute_t *this, linked_list_t *pools, identification_t *id, host_t *requested) { + enumerator_t *enumerator; host_t *address = NULL; u_int identity, pool, timeout; + char *name; identity = get_identity(this, id); if (identity) { - /* check for a single pool first (no concatenation and enumeration) */ - if (strchr(names, ',') == NULL) + /* check for an existing lease in all pools */ + enumerator = pools->create_enumerator(pools); + while (enumerator->enumerate(enumerator, &name)) { - pool = get_pool(this, names, &timeout); + pool = get_pool(this, name, &timeout); if (pool) { - /* check for an existing lease */ - address = check_lease(this, names, pool, identity); - if (address == NULL) + address = check_lease(this, name, pool, identity); + if (address) { - /* get an unallocated address or expired lease */ - address = get_lease(this, names, pool, timeout, identity); + break; } } } - else - { - enumerator_t *enumerator; - char *name; + enumerator->destroy(enumerator); - /* in a first step check for an existing lease over all pools */ - enumerator = enumerator_create_token(names, ",", " "); - while (enumerator->enumerate(enumerator, &name)) - { - pool = get_pool(this, name, &timeout); - if (pool) - { - address = check_lease(this, name, pool, identity); - if (address) - { - enumerator->destroy(enumerator); - return address; - } - } - } - enumerator->destroy(enumerator); - - /* in a second step get an unallocated address or expired lease */ - enumerator = enumerator_create_token(names, ",", " "); + if (!address) + { + /* get an unallocated address or expired lease */ + enumerator = pools->create_enumerator(pools); while (enumerator->enumerate(enumerator, &name)) { pool = get_pool(this, name, &timeout); @@ -300,20 +283,27 @@ METHOD(attribute_provider_t, acquire_address, host_t*, } METHOD(attribute_provider_t, release_address, bool, - private_sql_attribute_t *this, char *name, host_t *address, + private_sql_attribute_t *this, linked_list_t *pools, host_t *address, identification_t *id) { enumerator_t *enumerator; - bool found = FALSE; + u_int pool, timeout; time_t now = time(NULL); + bool found = FALSE; + char *name; - enumerator = enumerator_create_token(name, ",", " "); + enumerator = pools->create_enumerator(pools); while (enumerator->enumerate(enumerator, &name)) { - u_int pool, timeout; - pool = get_pool(this, name, &timeout); - if (pool) + if (!pool) + { + continue; + } + if (this->db->execute(this->db, NULL, + "UPDATE addresses SET released = ? WHERE " + "pool = ? AND address = ?", DB_UINT, time(NULL), + DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0) { if (this->history) { @@ -324,29 +314,24 @@ METHOD(attribute_provider_t, release_address, bool, DB_UINT, now, DB_UINT, pool, DB_BLOB, address->get_address(address)); } - if (this->db->execute(this->db, NULL, - "UPDATE addresses SET released = ? WHERE " - "pool = ? AND address = ?", DB_UINT, time(NULL), - DB_UINT, pool, DB_BLOB, address->get_address(address)) > 0) - { - found = TRUE; - break; - } + found = TRUE; + break; } } enumerator->destroy(enumerator); + return found; } METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, - private_sql_attribute_t *this, char *names, identification_t *id, - host_t *vip) + private_sql_attribute_t *this, linked_list_t *pools, identification_t *id, + linked_list_t *vips) { enumerator_t *attr_enumerator = NULL; - if (vip) + if (vips->get_count(vips)) { - enumerator_t *names_enumerator; + enumerator_t *pool_enumerator; u_int count; char *name; @@ -357,8 +342,8 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, { u_int identity = get_identity(this, id); - names_enumerator = enumerator_create_token(names, ",", " "); - while (names_enumerator->enumerate(names_enumerator, &name)) + pool_enumerator = pools->create_enumerator(pools); + while (pool_enumerator->enumerate(pool_enumerator, &name)) { u_int attr_pool = get_attr_pool(this, name); if (!attr_pool) @@ -385,14 +370,14 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, DESTROY_IF(attr_enumerator); attr_enumerator = NULL; } - names_enumerator->destroy(names_enumerator); + pool_enumerator->destroy(pool_enumerator); } /* in a second step check for attributes that match name */ if (!attr_enumerator) { - names_enumerator = enumerator_create_token(names, ",", " "); - while (names_enumerator->enumerate(names_enumerator, &name)) + pool_enumerator = pools->create_enumerator(pools); + while (pool_enumerator->enumerate(pool_enumerator, &name)) { u_int attr_pool = get_attr_pool(this, name); if (!attr_pool) @@ -419,7 +404,7 @@ METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*, DESTROY_IF(attr_enumerator); attr_enumerator = NULL; } - names_enumerator->destroy(names_enumerator); + pool_enumerator->destroy(pool_enumerator); } this->db->execute(this->db, NULL, "END TRANSACTION"); diff --git a/src/libhydra/plugins/kernel_klips/Makefile.in b/src/libhydra/plugins/kernel_klips/Makefile.in index 63f3e045b..1dd633ee2 100644 --- a/src/libhydra/plugins/kernel_klips/Makefile.in +++ b/src/libhydra/plugins/kernel_klips/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_kernel_klips_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_kernel_klips_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_kernel_klips_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c index ceff8cdc9..d875dab04 100644 --- a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c +++ b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c @@ -137,11 +137,6 @@ struct private_kernel_klips_ipsec_t */ linked_list_t *ipsec_devices; - /** - * job receiving PF_KEY events - */ - callback_job_t *job; - /** * mutex to lock access to the PF_KEY socket */ @@ -825,8 +820,22 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm ID and its key size */ -static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static int lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + int alg = 0; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + default: + return 0; + } while (list->ikev2 != END_OF_LIST) { if (ikev2 == list->ikev2) @@ -835,7 +844,9 @@ static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return 0; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, &alg, NULL); + return alg; } /** @@ -1525,12 +1536,12 @@ METHOD(kernel_ipsec_t, get_spi, status_t, u_int32_t spi_gen; rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->get_bytes(rng, sizeof(spi_gen), (void*)&spi_gen)) { - DBG1(DBG_KNL, "allocating SPI failed: no RNG"); + DBG1(DBG_KNL, "allocating SPI failed"); + DESTROY_IF(rng); return FAILED; } - rng->get_bytes(rng, sizeof(spi_gen), (void*)&spi_gen); rng->destroy(rng); /* allocated SPIs lie within the range from 0xc0000000 to 0xcFFFFFFF */ @@ -1718,8 +1729,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->sadb_sa_spi = spi; sa->sadb_sa_state = SADB_SASTATE_MATURE; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); PFKEY_EXT_ADD(msg, sa); add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC); @@ -2097,7 +2108,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, */ if (policy->route == NULL && direction == POLICY_OUT) { - char *iface; + char *iface = NULL; ipsec_dev_t *dev; route_entry_t *route = malloc_thing(route_entry_t); route->src_ip = NULL; @@ -2115,8 +2126,8 @@ METHOD(kernel_ipsec_t, add_policy, status_t, } /* find the virtual interface */ - iface = hydra->kernel_interface->get_interface(hydra->kernel_interface, - src); + hydra->kernel_interface->get_interface(hydra->kernel_interface, + src, &iface); if (find_ipsec_dev(this, iface, &dev) == SUCCESS) { /* above, we got either the name of a virtual or a physical @@ -2163,7 +2174,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, /* get the nexthop to dst */ route->gateway = hydra->kernel_interface->get_nexthop( - hydra->kernel_interface, dst); + hydra->kernel_interface, dst, route->src_ip); route->dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)); route->prefixlen = policy->dst.mask; @@ -2542,20 +2553,9 @@ static status_t register_pfkey_socket(private_kernel_klips_ipsec_t *this, u_int8 return SUCCESS; } -METHOD(kernel_ipsec_t, bypass_socket, bool, - private_kernel_klips_ipsec_t *this, int fd, int family) -{ - /* KLIPS does not need a bypass policy for IKE */ - return TRUE; -} - METHOD(kernel_ipsec_t, destroy, void, private_kernel_klips_ipsec_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } if (this->socket > 0) { close(this->socket); @@ -2594,7 +2594,10 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create() .query_policy = _query_policy, .del_policy = _del_policy, .flush_policies = (void*)return_failed, - .bypass_socket = _bypass_socket, + /* KLIPS does not need a bypass policy for IKE */ + .bypass_socket = (void*)return_true, + /* KLIPS does not need enabling UDP decap explicitly */ + .enable_udp_decap = (void*)return_true, .destroy = _destroy, }, }, @@ -2639,9 +2642,9 @@ kernel_klips_ipsec_t *kernel_klips_ipsec_create() return NULL; } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((callback_job_cb_t)receive_events, + this, NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); return &this->public; } diff --git a/src/libhydra/plugins/kernel_netlink/Makefile.in b/src/libhydra/plugins/kernel_netlink/Makefile.in index 73dbdd0e3..d0adb3b1e 100644 --- a/src/libhydra/plugins/kernel_netlink/Makefile.in +++ b/src/libhydra/plugins/kernel_netlink/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_kernel_netlink_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_kernel_netlink_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_kernel_netlink_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index b2cf778be..4f5b6600d 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2008 Andreas Steffen * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser @@ -58,6 +58,20 @@ #define IPV6_XFRM_POLICY 34 #endif /*IPV6_XFRM_POLICY*/ +/* from linux/udp.h */ +#ifndef UDP_ENCAP +#define UDP_ENCAP 100 +#endif + +#ifndef UDP_ENCAP_ESPINUDP +#define UDP_ENCAP_ESPINUDP 2 +#endif + +/* this is not defined on some platforms */ +#ifndef SOL_UDP +#define SOL_UDP IPPROTO_UDP +#endif + /** Default priority of installed policies */ #define PRIO_BASE 512 @@ -229,8 +243,25 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm name and its key size */ -static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static char* lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + char *name = NULL; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + case COMPRESSION_ALGORITHM: + list = compression_algs; + break; + default: + return NULL; + } while (list->ikev2 != END_OF_LIST) { if (list->ikev2 == ikev2) @@ -239,7 +270,9 @@ static char* lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return NULL; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, NULL, &name); + return name; } typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t; @@ -268,11 +301,6 @@ struct private_kernel_netlink_ipsec_t { */ hashtable_t *sas; - /** - * Job receiving netlink events - */ - callback_job_t *job; - /** * Netlink xfrm socket (IPsec) */ @@ -294,12 +322,12 @@ struct private_kernel_netlink_ipsec_t { bool policy_history; /** - * Size of the replay window, in packets + * Size of the replay window, in packets (= bits) */ u_int32_t replay_window; /** - * Size of the replay window bitmap, in bytes + * Size of the replay window bitmap, in number of __u32 blocks */ u_int32_t replay_bmp; }; @@ -344,8 +372,8 @@ static void route_entry_destroy(route_entry_t *this) static bool route_entry_equals(route_entry_t *a, route_entry_t *b) { return a->if_name && b->if_name && streq(a->if_name, b->if_name) && - a->src_ip->equals(a->src_ip, b->src_ip) && - a->gateway->equals(a->gateway, b->gateway) && + a->src_ip->ip_equals(a->src_ip, b->src_ip) && + a->gateway->ip_equals(a->gateway, b->gateway) && chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; } @@ -562,9 +590,8 @@ static void policy_entry_destroy(private_kernel_netlink_ipsec_t *this, */ static u_int policy_hash(policy_entry_t *key) { - chunk_t chunk = chunk_create((void*)&key->sel, - sizeof(struct xfrm_selector) + sizeof(u_int32_t)); - return chunk_hash(chunk); + chunk_t chunk = chunk_from_thing(key->sel); + return chunk_hash_inc(chunk, chunk_hash(chunk_from_thing(key->mark))); } /** @@ -572,8 +599,8 @@ static u_int policy_hash(policy_entry_t *key) */ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key) { - return memeq(&key->sel, &other_key->sel, - sizeof(struct xfrm_selector) + sizeof(u_int32_t)) && + return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) && + key->mark == other_key->mark && key->direction == other_key->direction; } @@ -1147,16 +1174,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, memset(&request, 0, sizeof(request)); - if (mark.value) - { - DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} (mark " - "%u/0x%8x)", ntohl(spi), reqid, mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u}", - ntohl(spi), reqid); - } + DBG2(DBG_KNL, "adding SAD entry with SPI %.8x and reqid {%u} (mark " + "%u/0x%08x)", ntohl(spi), reqid, mark.value, mark.mask); + hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; hdr->nlmsg_type = inbound ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; @@ -1220,12 +1240,12 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo_aead *algo; - alg_name = lookup_algorithm(encryption_algs, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", - encryption_algorithm_names, enc_alg); - goto failed; + encryption_algorithm_names, enc_alg); + goto failed; } DBG2(DBG_KNL, " using encryption algorithm %N with key size %d", encryption_algorithm_names, enc_alg, enc_key.len * 8); @@ -1242,7 +1262,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo = (struct xfrm_algo_aead*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; algo->alg_icv_len = icv_size; - strcpy(algo->alg_name, alg_name); + strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); + algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); rthdr = XFRM_RTA_NEXT(rthdr); @@ -1252,7 +1273,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { struct xfrm_algo *algo; - alg_name = lookup_algorithm(encryption_algs, enc_alg); + alg_name = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1272,7 +1293,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = enc_key.len * 8; - strcpy(algo->alg_name, alg_name); + strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); + algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, enc_key.ptr, enc_key.len); rthdr = XFRM_RTA_NEXT(rthdr); @@ -1283,7 +1305,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, { u_int trunc_len = 0; - alg_name = lookup_algorithm(integrity_algs, int_alg); + alg_name = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1326,7 +1348,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo = (struct xfrm_algo_auth*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; algo->alg_trunc_len = trunc_len; - strcpy(algo->alg_name, alg_name); + strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); + algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, int_key.ptr, int_key.len); } else @@ -1344,7 +1367,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = int_key.len * 8; - strcpy(algo->alg_name, alg_name); + strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); + algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; memcpy(algo->alg_key, int_key.ptr, int_key.len); } rthdr = XFRM_RTA_NEXT(rthdr); @@ -1353,7 +1377,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, if (ipcomp != IPCOMP_NONE) { rthdr->rta_type = XFRMA_ALG_COMP; - alg_name = lookup_algorithm(compression_algs, ipcomp); + alg_name = lookup_algorithm(COMPRESSION_ALGORITHM, ipcomp); if (alg_name == NULL) { DBG1(DBG_KNL, "algorithm %N not supported by kernel!", @@ -1372,7 +1396,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, struct xfrm_algo* algo = (struct xfrm_algo*)RTA_DATA(rthdr); algo->alg_key_len = 0; - strcpy(algo->alg_name, alg_name); + strncpy(algo->alg_name, alg_name, sizeof(algo->alg_name)); + algo->alg_name[sizeof(algo->alg_name) - 1] = '\0'; rthdr = XFRM_RTA_NEXT(rthdr); } @@ -1467,7 +1492,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, /* bmp_len contains number uf __u32's */ replay->bmp_len = this->replay_bmp; replay->replay_window = this->replay_window; - DBG2(DBG_KNL, " using replay window of %u bytes", + DBG2(DBG_KNL, " using replay window of %u packets", this->replay_window); rthdr = XFRM_RTA_NEXT(rthdr); @@ -1479,7 +1504,9 @@ METHOD(kernel_ipsec_t, add_sa, status_t, } else { - sa->replay_window = DEFAULT_REPLAY_WINDOW; + DBG2(DBG_KNL, " using replay window of %u packets", + this->replay_window); + sa->replay_window = this->replay_window; } } @@ -1488,7 +1515,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t, if (mark.value) { DBG1(DBG_KNL, "unable to add SAD entry with SPI %.8x " - "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); + "(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); } else { @@ -1608,15 +1635,9 @@ METHOD(kernel_ipsec_t, query_sa, status_t, memset(&request, 0, sizeof(request)); - if (mark.value) - { - DBG2(DBG_KNL, "querying SAD entry with SPI %.8x (mark %u/0x%8x)", - ntohl(spi), mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "querying SAD entry with SPI %.8x", ntohl(spi)); - } + DBG2(DBG_KNL, "querying SAD entry with SPI %.8x (mark %u/0x%08x)", + ntohl(spi), mark.value, mark.mask); + hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; hdr->nlmsg_type = XFRM_MSG_GETSA; @@ -1665,7 +1686,7 @@ METHOD(kernel_ipsec_t, query_sa, status_t, if (mark.value) { DBG1(DBG_KNL, "querying SAD entry with SPI %.8x " - "(mark %u/0x%8x) failed: %s (%d)", + "(mark %u/0x%08x) failed: %s (%d)", ntohl(spi), mark.value, mark.mask, strerror(-err->error), -err->error); } @@ -1717,15 +1738,9 @@ METHOD(kernel_ipsec_t, del_sa, status_t, memset(&request, 0, sizeof(request)); - if (mark.value) - { - DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x (mark %u/0x%8x)", - ntohl(spi), mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x", ntohl(spi)); - } + DBG2(DBG_KNL, "deleting SAD entry with SPI %.8x (mark %u/0x%08x)", + ntohl(spi), mark.value, mark.mask); + hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; hdr->nlmsg_type = XFRM_MSG_DELSA; @@ -1755,30 +1770,27 @@ METHOD(kernel_ipsec_t, del_sa, status_t, mrk->m = mark.mask; } - if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) - { - if (mark.value) - { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " - "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); - } - else - { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", - ntohl(spi)); - } - return FAILED; - } - if (mark.value) + switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr)) { - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%8x)", - ntohl(spi), mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); + case SUCCESS: + DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)", + ntohl(spi), mark.value, mark.mask); + return SUCCESS; + case NOT_FOUND: + return NOT_FOUND; + default: + if (mark.value) + { + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " + "(mark %u/0x%08x)", ntohl(spi), mark.value, mark.mask); + } + else + { + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", + ntohl(spi)); + } + return FAILED; } - return SUCCESS; } METHOD(kernel_ipsec_t, update_sa, status_t, @@ -1954,7 +1966,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, { goto failed; } - memcpy(RTA_DATA(rta), replay, sizeof(replay)); + memcpy(RTA_DATA(rta), replay, sizeof(struct xfrm_replay_state)); rta = XFRM_RTA_NEXT(rta); } @@ -2153,23 +2165,26 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, if (policy->direction == POLICY_FWD && ipsec->cfg.mode != MODE_TRANSPORT && this->install_routes) { - route_entry_t *route = malloc_thing(route_entry_t); policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)mapping; + route_entry_t *route; + + INIT(route, + .prefixlen = policy->sel.prefixlen_s, + ); if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface, fwd->dst_ts, &route->src_ip) == SUCCESS) { /* get the nexthop to src (src as we are in POLICY_FWD) */ route->gateway = hydra->kernel_interface->get_nexthop( - hydra->kernel_interface, ipsec->src); - /* install route via outgoing interface */ - route->if_name = hydra->kernel_interface->get_interface( - hydra->kernel_interface, ipsec->dst); + hydra->kernel_interface, ipsec->src, + ipsec->dst); route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); memcpy(route->dst_net.ptr, &policy->sel.saddr, route->dst_net.len); - route->prefixlen = policy->sel.prefixlen_s; - if (!route->if_name) + /* install route via outgoing interface */ + if (!hydra->kernel_interface->get_interface(hydra->kernel_interface, + ipsec->dst, &route->if_name)) { this->mutex->unlock(this->mutex); route_entry_destroy(route); @@ -2180,12 +2195,7 @@ static status_t add_policy_internal(private_kernel_netlink_ipsec_t *this, { route_entry_t *old = policy->route; if (route_entry_equals(old, route)) - { /* keep previously installed route. since it might have - * still been removed by an address change, we install it - * again but ignore the result */ - hydra->kernel_interface->add_route(hydra->kernel_interface, - route->dst_net, route->prefixlen, route->gateway, - route->src_ip, route->if_name); + { this->mutex->unlock(this->mutex); route_entry_destroy(route); return SUCCESS; @@ -2258,19 +2268,10 @@ METHOD(kernel_ipsec_t, add_policy, status_t, if (current) { /* use existing policy */ - if (mark.value) - { - DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%8x) " - "already exists, increasing refcount", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "policy %R === %R %N " - "already exists, increasing refcount", - src_ts, dst_ts, policy_dir_names, direction); - } + DBG2(DBG_KNL, "policy %R === %R %N (mark %u/0x%08x) " + "already exists, increasing refcount", + src_ts, dst_ts, policy_dir_names, direction, + mark.value, mark.mask); policy_entry_destroy(this, policy); policy = current; found = TRUE; @@ -2314,18 +2315,9 @@ METHOD(kernel_ipsec_t, add_policy, status_t, return SUCCESS; } - if (mark.value) - { - DBG2(DBG_KNL, "%s policy %R === %R %N (mark %u/0x%8x)", - found ? "updating" : "adding", src_ts, dst_ts, - policy_dir_names, direction, mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "%s policy %R === %R %N", - found ? "updating" : "adding", src_ts, dst_ts, - policy_dir_names, direction); - } + DBG2(DBG_KNL, "%s policy %R === %R %N (mark %u/0x%08x)", + found ? "updating" : "adding", src_ts, dst_ts, + policy_dir_names, direction, mark.value, mark.mask); if (add_policy_internal(this, policy, assigned_sa, found) != SUCCESS) { @@ -2350,17 +2342,10 @@ METHOD(kernel_ipsec_t, query_policy, status_t, memset(&request, 0, sizeof(request)); - if (mark.value) - { - DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%8x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "querying policy %R === %R %N", src_ts, dst_ts, - policy_dir_names, direction); - } + DBG2(DBG_KNL, "querying policy %R === %R %N (mark %u/0x%08x)", + src_ts, dst_ts, policy_dir_names, direction, + mark.value, mark.mask); + hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; hdr->nlmsg_type = XFRM_MSG_GETPOLICY; @@ -2454,17 +2439,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, bool is_installed = TRUE; u_int32_t priority; - if (mark.value) - { - DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%8x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "deleting policy %R === %R %N", - src_ts, dst_ts, policy_dir_names, direction); - } + DBG2(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x)", + src_ts, dst_ts, policy_dir_names, direction, + mark.value, mark.mask); /* create a policy */ memset(&policy, 0, sizeof(policy_entry_t)); @@ -2479,7 +2456,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, { if (mark.value) { - DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%8x) " + DBG1(DBG_KNL, "deleting policy %R === %R %N (mark %u/0x%08x) " "failed, not found", src_ts, dst_ts, policy_dir_names, direction, mark.value, mark.mask); } @@ -2525,17 +2502,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, return SUCCESS; } - if (mark.value) - { - DBG2(DBG_KNL, "updating policy %R === %R %N (mark %u/0x%8x)", - src_ts, dst_ts, policy_dir_names, direction, - mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "updating policy %R === %R %N", - src_ts, dst_ts, policy_dir_names, direction); - } + DBG2(DBG_KNL, "updating policy %R === %R %N (mark %u/0x%08x)", + src_ts, dst_ts, policy_dir_names, direction, + mark.value, mark.mask); current->used_by->get_first(current->used_by, (void**)&mapping); if (add_policy_internal(this, current, mapping, TRUE) != SUCCESS) @@ -2599,7 +2568,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t, if (mark.value) { DBG1(DBG_KNL, "unable to delete policy %R === %R %N " - "(mark %u/0x%8x)", src_ts, dst_ts, policy_dir_names, + "(mark %u/0x%08x)", src_ts, dst_ts, policy_dir_names, direction, mark.value, mark.mask); } else @@ -2680,16 +2649,25 @@ METHOD(kernel_ipsec_t, bypass_socket, bool, return TRUE; } +METHOD(kernel_ipsec_t, enable_udp_decap, bool, + private_kernel_netlink_ipsec_t *this, int fd, int family, u_int16_t port) +{ + int type = UDP_ENCAP_ESPINUDP; + + if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) + { + DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno)); + return FALSE; + } + return TRUE; +} + METHOD(kernel_ipsec_t, destroy, void, private_kernel_netlink_ipsec_t *this) { enumerator_t *enumerator; policy_entry_t *policy; - if (this->job) - { - this->job->cancel(this->job); - } if (this->socket_xfrm_events > 0) { close(this->socket_xfrm_events); @@ -2713,7 +2691,7 @@ METHOD(kernel_ipsec_t, destroy, void, kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() { private_kernel_netlink_ipsec_t *this; - struct sockaddr_nl addr; + bool register_for_events = TRUE; int fd; INIT(this, @@ -2731,6 +2709,7 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() .del_policy = _del_policy, .flush_policies = _flush_policies, .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, .destroy = _destroy, }, }, @@ -2755,10 +2734,14 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() /* no policy history for pluto */ this->policy_history = FALSE; } + else if (streq(hydra->daemon, "starter")) + { /* starter has no threads, so we do not register for kernel events */ + register_for_events = FALSE; + } /* disable lifetimes for allocated SPIs in kernel */ fd = open("/proc/sys/net/core/xfrm_acq_expires", O_WRONLY); - if (fd) + if (fd > 0) { ignore_result(write(fd, "165", 3)); close(fd); @@ -2771,28 +2754,34 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create() return NULL; } - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - - /* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */ - this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); - if (this->socket_xfrm_events <= 0) + if (register_for_events) { - DBG1(DBG_KNL, "unable to create XFRM event socket"); - destroy(this); - return NULL; - } - addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) | - XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING); - if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) - { - DBG1(DBG_KNL, "unable to bind XFRM event socket"); - destroy(this); - return NULL; + struct sockaddr_nl addr; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + + /* create and bind XFRM socket for ACQUIRE, EXPIRE, MIGRATE & MAPPING */ + this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM); + if (this->socket_xfrm_events <= 0) + { + DBG1(DBG_KNL, "unable to create XFRM event socket"); + destroy(this); + return NULL; + } + addr.nl_groups = XFRMNLGRP(ACQUIRE) | XFRMNLGRP(EXPIRE) | + XFRMNLGRP(MIGRATE) | XFRMNLGRP(MAPPING); + if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr))) + { + DBG1(DBG_KNL, "unable to bind XFRM event socket"); + destroy(this); + return NULL; + } + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)receive_events, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); return &this->public; } diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c index cce0ff402..3f63a8496 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -38,6 +38,7 @@ */ #include +#include #include #include #include @@ -50,32 +51,38 @@ #include #include #include -#include #include +#include +#include +#include +#include #include #include /** delay before firing roam events (ms) */ #define ROAM_DELAY 100 +/** delay before reinstalling routes (ms) */ +#define ROUTE_DELAY 100 + typedef struct addr_entry_t addr_entry_t; /** - * IP address in an inface_entry_t + * IP address in an iface_entry_t */ struct addr_entry_t { - /** The ip address */ + /** the ip address */ host_t *ip; - /** virtual IP managed by us */ - bool virtual; - /** scope of the address */ u_char scope; - /** Number of times this IP is used, if virtual */ + /** number of times this IP is used, if virtual (i.e. managed by us) */ u_int refcount; + + /** TRUE once it is installed, if virtual */ + bool installed; }; /** @@ -105,6 +112,9 @@ struct iface_entry_t { /** list of addresses as host_t */ linked_list_t *addrs; + + /** TRUE if usable by config */ + bool usable; }; /** @@ -116,6 +126,208 @@ static void iface_entry_destroy(iface_entry_t *this) free(this); } +/** + * find an interface entry by index + */ +static bool iface_entry_by_index(iface_entry_t *this, int *ifindex) +{ + return this->ifindex == *ifindex; +} + +/** + * find an interface entry by name + */ +static bool iface_entry_by_name(iface_entry_t *this, char *ifname) +{ + return streq(this->ifname, ifname); +} + +/** + * check if an interface is up + */ +static inline bool iface_entry_up(iface_entry_t *iface) +{ + return (iface->flags & IFF_UP) == IFF_UP; +} + +/** + * check if an interface is up and usable + */ +static inline bool iface_entry_up_and_usable(iface_entry_t *iface) +{ + return iface->usable && iface_entry_up(iface); +} + +typedef struct addr_map_entry_t addr_map_entry_t; + +/** + * Entry that maps an IP address to an interface entry + */ +struct addr_map_entry_t { + /** The IP address */ + host_t *ip; + + /** The address entry for this IP address */ + addr_entry_t *addr; + + /** The interface this address is installed on */ + iface_entry_t *iface; +}; + +/** + * Hash a addr_map_entry_t object, all entries with the same IP address + * are stored in the same bucket + */ +static u_int addr_map_entry_hash(addr_map_entry_t *this) +{ + return chunk_hash(this->ip->get_address(this->ip)); +} + +/** + * Compare two addr_map_entry_t objects, two entries are equal if they are + * installed on the same interface + */ +static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b) +{ + return a->iface->ifindex == b->iface->ifindex && + a->ip->ip_equals(a->ip, b->ip); +} + +/** + * Used with get_match this finds an address entry if it is installed on + * an up and usable interface + */ +static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a, + addr_map_entry_t *b) +{ + return iface_entry_up_and_usable(b->iface) && + a->ip->ip_equals(a->ip, b->ip); +} + +/** + * Used with get_match this finds an address entry if it is installed on + * any active local interface + */ +static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b) +{ + return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip); +} + +/** + * Used with get_match this finds an address entry if it is installed on + * any local interface + */ +static bool addr_map_entry_match(addr_map_entry_t *a, addr_map_entry_t *b) +{ + return a->ip->ip_equals(a->ip, b->ip); +} + +typedef struct route_entry_t route_entry_t; + +/** + * Installed routing entry + */ +struct route_entry_t { + /** Name of the interface the route is bound to */ + char *if_name; + + /** Source ip of the route */ + host_t *src_ip; + + /** Gateway for this route */ + host_t *gateway; + + /** Destination net */ + chunk_t dst_net; + + /** Destination net prefixlen */ + u_int8_t prefixlen; +}; + +/** + * Clone a route_entry_t object. + */ +static route_entry_t *route_entry_clone(route_entry_t *this) +{ + route_entry_t *route; + + INIT(route, + .if_name = strdup(this->if_name), + .src_ip = this->src_ip->clone(this->src_ip), + .gateway = this->gateway->clone(this->gateway), + .dst_net = chunk_clone(this->dst_net), + .prefixlen = this->prefixlen, + ); + return route; +} + +/** + * Destroy a route_entry_t object + */ +static void route_entry_destroy(route_entry_t *this) +{ + free(this->if_name); + DESTROY_IF(this->src_ip); + DESTROY_IF(this->gateway); + chunk_free(&this->dst_net); + free(this); +} + +/** + * Hash a route_entry_t object + */ +static u_int route_entry_hash(route_entry_t *this) +{ + return chunk_hash_inc(chunk_from_thing(this->prefixlen), + chunk_hash(this->dst_net)); +} + +/** + * Compare two route_entry_t objects + */ +static bool route_entry_equals(route_entry_t *a, route_entry_t *b) +{ + return a->if_name && b->if_name && streq(a->if_name, b->if_name) && + a->src_ip->ip_equals(a->src_ip, b->src_ip) && + a->gateway->ip_equals(a->gateway, b->gateway) && + chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; +} + +typedef struct net_change_t net_change_t; + +/** + * Queued network changes + */ +struct net_change_t { + /** Name of the interface that got activated (or an IP appeared on) */ + char *if_name; +}; + +/** + * Destroy a net_change_t object + */ +static void net_change_destroy(net_change_t *this) +{ + free(this->if_name); + free(this); +} + +/** + * Hash a net_change_t object + */ +static u_int net_change_hash(net_change_t *this) +{ + return chunk_hash(chunk_create(this->if_name, strlen(this->if_name))); +} + +/** + * Compare two net_change_t objects + */ +static bool net_change_equals(net_change_t *a, net_change_t *b) +{ + return streq(a->if_name, b->if_name); +} + typedef struct private_kernel_netlink_net_t private_kernel_netlink_net_t; /** @@ -128,14 +340,14 @@ struct private_kernel_netlink_net_t { kernel_netlink_net_t public; /** - * mutex to lock access to various lists + * lock to access various lists and maps */ - mutex_t *mutex; + rwlock_t *lock; /** * condition variable to signal virtual IP add/removal */ - condvar_t *condvar; + rwlock_condvar_t *condvar; /** * Cached list of interfaces and its addresses (iface_entry_t) @@ -143,9 +355,14 @@ struct private_kernel_netlink_net_t { linked_list_t *ifaces; /** - * job receiving netlink events + * Map for IP addresses to iface_entry_t objects (addr_map_entry_t) */ - callback_job_t *job; + hashtable_t *addrs; + + /** + * Map for virtual IP addresses to iface_entry_t objects (addr_map_entry_t) + */ + hashtable_t *vips; /** * netlink rt socket (routing) @@ -158,9 +375,14 @@ struct private_kernel_netlink_net_t { int socket_events; /** - * time of the last roam event + * earliest time of the next roam event */ - timeval_t last_roam; + timeval_t next_roam; + + /** + * lock to check and update roam event time + */ + spinlock_t *roam_lock; /** * routing table to install routes @@ -172,6 +394,31 @@ struct private_kernel_netlink_net_t { */ int routing_table_prio; + /** + * installed routes + */ + hashtable_t *routes; + + /** + * mutex for routes + */ + mutex_t *routes_lock; + + /** + * interface changes which may trigger route reinstallation + */ + hashtable_t *net_changes; + + /** + * mutex for route reinstallation triggers + */ + mutex_t *net_changes_lock; + + /** + * time of last route reinstallation + */ + timeval_t last_route_reinstall; + /** * whether to react to RTM_NEWROUTE or RTM_DELROUTE events */ @@ -182,6 +429,16 @@ struct private_kernel_netlink_net_t { */ bool install_virtual_ip; + /** + * the name of the interface virtual IP addresses are installed on + */ + char *install_virtual_ip_on; + + /** + * whether preferred source addresses can be specified for IPv6 routes + */ + bool rta_prefsrc_for_ipv6; + /** * list with routing tables to be excluded from route lookup */ @@ -189,73 +446,237 @@ struct private_kernel_netlink_net_t { }; /** - * get the refcount of a virtual ip + * Forward declaration */ -static int get_vip_refcount(private_kernel_netlink_net_t *this, host_t* ip) +static status_t manage_srcroute(private_kernel_netlink_net_t *this, + int nlmsg_type, int flags, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, + host_t *src_ip, char *if_name); + +/** + * Clear the queued network changes. + */ +static void net_changes_clear(private_kernel_netlink_net_t *this) { - enumerator_t *ifaces, *addrs; - iface_entry_t *iface; - addr_entry_t *addr; - int refcount = 0; + enumerator_t *enumerator; + net_change_t *change; - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, (void**)&iface)) + enumerator = this->net_changes->create_enumerator(this->net_changes); + while (enumerator->enumerate(enumerator, NULL, (void**)&change)) { - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, (void**)&addr)) - { - if (addr->virtual && (iface->flags & IFF_UP) && - ip->ip_equals(ip, addr->ip)) + this->net_changes->remove_at(this->net_changes, enumerator); + net_change_destroy(change); + } + enumerator->destroy(enumerator); +} + +/** + * Act upon queued network changes. + */ +static job_requeue_t reinstall_routes(private_kernel_netlink_net_t *this) +{ + enumerator_t *enumerator; + route_entry_t *route; + + this->net_changes_lock->lock(this->net_changes_lock); + this->routes_lock->lock(this->routes_lock); + + enumerator = this->routes->create_enumerator(this->routes); + while (enumerator->enumerate(enumerator, NULL, (void**)&route)) + { + net_change_t *change, lookup = { + .if_name = route->if_name, + }; + /* check if a change for the outgoing interface is queued */ + change = this->net_changes->get(this->net_changes, &lookup); + if (!change) + { /* in case src_ip is not on the outgoing interface */ + if (this->public.interface.get_interface(&this->public.interface, + route->src_ip, &lookup.if_name)) { - refcount = addr->refcount; - break; + if (!streq(lookup.if_name, route->if_name)) + { + change = this->net_changes->get(this->net_changes, &lookup); + } + free(lookup.if_name); } } - addrs->destroy(addrs); - if (refcount) + if (change) { - break; + manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, + route->dst_net, route->prefixlen, route->gateway, + route->src_ip, route->if_name); } } - ifaces->destroy(ifaces); + enumerator->destroy(enumerator); + this->routes_lock->unlock(this->routes_lock); - return refcount; + net_changes_clear(this); + this->net_changes_lock->unlock(this->net_changes_lock); + return JOB_REQUEUE_NONE; +} + +/** + * Queue route reinstallation caused by network changes for a given interface. + * + * The route reinstallation is delayed for a while and only done once for + * several calls during this delay, in order to avoid doing it too often. + * The interface name is freed. + */ +static void queue_route_reinstall(private_kernel_netlink_net_t *this, + char *if_name) +{ + net_change_t *update, *found; + timeval_t now; + job_t *job; + + INIT(update, + .if_name = if_name + ); + + this->net_changes_lock->lock(this->net_changes_lock); + found = this->net_changes->put(this->net_changes, update, update); + if (found) + { + net_change_destroy(found); + } + time_monotonic(&now); + if (timercmp(&now, &this->last_route_reinstall, >)) + { + now.tv_usec += ROUTE_DELAY * 1000; + while (now.tv_usec > 1000000) + { + now.tv_sec++; + now.tv_usec -= 1000000; + } + this->last_route_reinstall = now; + + job = (job_t*)callback_job_create((callback_job_cb_t)reinstall_routes, + this, NULL, NULL); + lib->scheduler->schedule_job_ms(lib->scheduler, job, ROUTE_DELAY); + } + this->net_changes_lock->unlock(this->net_changes_lock); +} + +/** + * check if the given IP is known as virtual IP and currently installed + * + * this function will also return TRUE if the virtual IP entry disappeared. + * in that case the returned entry will be NULL. + * + * this->lock must be held when calling this function + */ +static bool is_vip_installed_or_gone(private_kernel_netlink_net_t *this, + host_t *ip, addr_map_entry_t **entry) +{ + addr_map_entry_t lookup = { + .ip = ip, + }; + + *entry = this->vips->get_match(this->vips, &lookup, + (void*)addr_map_entry_match); + if (*entry == NULL) + { /* the virtual IP disappeared */ + return TRUE; + } + return (*entry)->addr->installed; +} + +/** + * check if the given IP is known as virtual IP + * + * this->lock must be held when calling this function + */ +static bool is_known_vip(private_kernel_netlink_net_t *this, host_t *ip) +{ + addr_map_entry_t lookup = { + .ip = ip, + }; + + return this->vips->get_match(this->vips, &lookup, + (void*)addr_map_entry_match) != NULL; +} + +/** + * Add an address map entry + */ +static void addr_map_entry_add(hashtable_t *map, addr_entry_t *addr, + iface_entry_t *iface) +{ + addr_map_entry_t *entry; + + INIT(entry, + .ip = addr->ip, + .addr = addr, + .iface = iface, + ); + entry = map->put(map, entry, entry); + free(entry); +} + +/** + * Remove an address map entry + */ +static void addr_map_entry_remove(hashtable_t *map, addr_entry_t *addr, + iface_entry_t *iface) +{ + addr_map_entry_t *entry, lookup = { + .ip = addr->ip, + .addr = addr, + .iface = iface, + }; + + entry = map->remove(map, &lookup); + free(entry); } /** * get the first non-virtual ip address on the given interface. + * if a candidate address is given, we first search for that address and if not + * found return the address as above. * returned host is a clone, has to be freed by caller. + * + * this->lock must be held when calling this function */ static host_t *get_interface_address(private_kernel_netlink_net_t *this, - int ifindex, int family) + int ifindex, int family, host_t *candidate) { - enumerator_t *ifaces, *addrs; iface_entry_t *iface; + enumerator_t *addrs; addr_entry_t *addr; host_t *ip = NULL; - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) + if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, + (void**)&iface, &ifindex) == SUCCESS) { - if (iface->ifindex == ifindex) - { + if (iface->usable) + { /* only use interfaces not excluded by config */ addrs = iface->addrs->create_enumerator(iface->addrs); while (addrs->enumerate(addrs, &addr)) { - if (!addr->virtual && addr->ip->get_family(addr->ip) == family) + if (addr->refcount) + { /* ignore virtual IP addresses */ + continue; + } + if (addr->ip->get_family(addr->ip) == family) { - ip = addr->ip->clone(addr->ip); - break; + if (!candidate || candidate->ip_equals(candidate, addr->ip)) + { /* stop at the first address if we don't search for a + * candidate or if the candidate matches */ + ip = addr->ip; + break; + } + else if (!ip) + { /* store the first address as fallback if candidate is + * not found */ + ip = addr->ip; + } } } addrs->destroy(addrs); - break; } } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - return ip; + return ip ? ip->clone(ip) : NULL; } /** @@ -277,21 +698,60 @@ static void fire_roam_event(private_kernel_netlink_net_t *this, bool address) job_t *job; time_monotonic(&now); - if (timercmp(&now, &this->last_roam, >)) + this->roam_lock->lock(this->roam_lock); + if (!timercmp(&now, &this->next_roam, >)) { - now.tv_usec += ROAM_DELAY * 1000; - while (now.tv_usec > 1000000) - { - now.tv_sec++; - now.tv_usec -= 1000000; - } - this->last_roam = now; + this->roam_lock->unlock(this->roam_lock); + return; + } + now.tv_usec += ROAM_DELAY * 1000; + while (now.tv_usec > 1000000) + { + now.tv_sec++; + now.tv_usec -= 1000000; + } + this->next_roam = now; + this->roam_lock->unlock(this->roam_lock); + + job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, + (void*)(uintptr_t)(address ? 1 : 0), + NULL, NULL); + lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY); +} - job = (job_t*)callback_job_create((callback_job_cb_t)roam_event, - (void*)(uintptr_t)(address ? 1 : 0), - NULL, NULL); - lib->scheduler->schedule_job_ms(lib->scheduler, job, ROAM_DELAY); +/** + * check if an interface with a given index is up and usable + * + * this->lock must be locked when calling this function + */ +static bool is_interface_up_and_usable(private_kernel_netlink_net_t *this, + int index) +{ + iface_entry_t *iface; + + if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, + (void**)&iface, &index) == SUCCESS) + { + return iface_entry_up_and_usable(iface); } + return FALSE; +} + +/** + * unregister the current addr_entry_t from the hashtable it is stored in + * + * this->lock must be locked when calling this function + */ +static void addr_entry_unregister(addr_entry_t *addr, iface_entry_t *iface, + private_kernel_netlink_net_t *this) +{ + if (addr->refcount) + { + addr_map_entry_remove(this->vips, addr, iface); + this->condvar->broadcast(this->condvar); + return; + } + addr_map_entry_remove(this->addrs, addr, iface); } /** @@ -306,9 +766,9 @@ static void process_link(private_kernel_netlink_net_t *this, enumerator_t *enumerator; iface_entry_t *current, *entry = NULL; char *name = NULL; - bool update = FALSE; + bool update = FALSE, update_routes = FALSE; - while(RTA_OK(rta, rtasize)) + while (RTA_OK(rta, rtasize)) { switch (rta->rta_type) { @@ -323,40 +783,30 @@ static void process_link(private_kernel_netlink_net_t *this, name = "(unknown)"; } - this->mutex->lock(this->mutex); + this->lock->write_lock(this->lock); switch (hdr->nlmsg_type) { case RTM_NEWLINK: { - if (msg->ifi_flags & IFF_LOOPBACK) - { /* ignore loopback interfaces */ - break; - } - enumerator = this->ifaces->create_enumerator(this->ifaces); - while (enumerator->enumerate(enumerator, ¤t)) + if (this->ifaces->find_first(this->ifaces, + (void*)iface_entry_by_index, (void**)&entry, + &msg->ifi_index) != SUCCESS) { - if (current->ifindex == msg->ifi_index) - { - entry = current; - break; - } - } - enumerator->destroy(enumerator); - if (!entry) - { - entry = malloc_thing(iface_entry_t); - entry->ifindex = msg->ifi_index; - entry->flags = 0; - entry->addrs = linked_list_create(); + INIT(entry, + .ifindex = msg->ifi_index, + .addrs = linked_list_create(), + .usable = hydra->kernel_interface->is_interface_usable( + hydra->kernel_interface, name), + ); this->ifaces->insert_last(this->ifaces, entry); } strncpy(entry->ifname, name, IFNAMSIZ); entry->ifname[IFNAMSIZ-1] = '\0'; - if (event) + if (event && entry->usable) { if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP)) { - update = TRUE; + update = update_routes = TRUE; DBG1(DBG_KNL, "interface %s activated", name); } if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP)) @@ -375,12 +825,16 @@ static void process_link(private_kernel_netlink_net_t *this, { if (current->ifindex == msg->ifi_index) { - if (event) + if (event && current->usable) { update = TRUE; DBG1(DBG_KNL, "interface %s deleted", current->ifname); } + /* TODO: move virtual IPs installed on this interface to + * another interface? */ this->ifaces->remove_at(this->ifaces, enumerator); + current->addrs->invoke_function(current->addrs, + (void*)addr_entry_unregister, current, this); iface_entry_destroy(current); break; } @@ -389,9 +843,13 @@ static void process_link(private_kernel_netlink_net_t *this, break; } } - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); + + if (update_routes && event) + { + queue_route_reinstall(this, strdup(name)); + } - /* send an update to all IKE_SAs */ if (update && event) { fire_roam_event(this, TRUE); @@ -408,13 +866,12 @@ static void process_addr(private_kernel_netlink_net_t *this, struct rtattr *rta = IFA_RTA(msg); size_t rtasize = IFA_PAYLOAD (hdr); host_t *host = NULL; - enumerator_t *ifaces, *addrs; iface_entry_t *iface; - addr_entry_t *addr; chunk_t local = chunk_empty, address = chunk_empty; + char *route_ifname = NULL; bool update = FALSE, found = FALSE, changed = FALSE; - while(RTA_OK(rta, rtasize)) + while (RTA_OK(rta, rtasize)) { switch (rta->rta_type) { @@ -447,65 +904,92 @@ static void process_addr(private_kernel_netlink_net_t *this, return; } - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) + this->lock->write_lock(this->lock); + if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_index, + (void**)&iface, &msg->ifa_index) == SUCCESS) { - if (iface->ifindex == msg->ifa_index) + addr_map_entry_t *entry, lookup = { + .ip = host, + .iface = iface, + }; + addr_entry_t *addr; + + entry = this->vips->get(this->vips, &lookup); + if (entry) { - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, &addr)) + if (hdr->nlmsg_type == RTM_NEWADDR) + { /* mark as installed and signal waiting threads */ + entry->addr->installed = TRUE; + } + else + { /* the address was already marked as uninstalled */ + addr = entry->addr; + iface->addrs->remove(iface->addrs, addr, NULL); + addr_map_entry_remove(this->vips, addr, iface); + addr_entry_destroy(addr); + } + /* no roam events etc. for virtual IPs */ + this->condvar->broadcast(this->condvar); + this->lock->unlock(this->lock); + host->destroy(host); + return; + } + entry = this->addrs->get(this->addrs, &lookup); + if (entry) + { + if (hdr->nlmsg_type == RTM_DELADDR) { - if (host->ip_equals(host, addr->ip)) + found = TRUE; + addr = entry->addr; + iface->addrs->remove(iface->addrs, addr, NULL); + if (iface->usable) { - found = TRUE; - if (hdr->nlmsg_type == RTM_DELADDR) - { - iface->addrs->remove_at(iface->addrs, addrs); - if (!addr->virtual) - { - changed = TRUE; - DBG1(DBG_KNL, "%H disappeared from %s", - host, iface->ifname); - } - addr_entry_destroy(addr); - } - else if (hdr->nlmsg_type == RTM_NEWADDR && addr->virtual) - { - addr->refcount = 1; - } + changed = TRUE; + DBG1(DBG_KNL, "%H disappeared from %s", host, + iface->ifname); } + addr_map_entry_remove(this->addrs, addr, iface); + addr_entry_destroy(addr); } - addrs->destroy(addrs); - + } + else + { if (hdr->nlmsg_type == RTM_NEWADDR) { - if (!found) + found = TRUE; + changed = TRUE; + route_ifname = strdup(iface->ifname); + INIT(addr, + .ip = host->clone(host), + .scope = msg->ifa_scope, + ); + iface->addrs->insert_last(iface->addrs, addr); + addr_map_entry_add(this->addrs, addr, iface); + if (event && iface->usable) { - found = TRUE; - changed = TRUE; - addr = malloc_thing(addr_entry_t); - addr->ip = host->clone(host); - addr->virtual = FALSE; - addr->refcount = 1; - addr->scope = msg->ifa_scope; - - iface->addrs->insert_last(iface->addrs, addr); - if (event) - { - DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname); - } + DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname); } } - if (found && (iface->flags & IFF_UP)) - { - update = TRUE; - } - break; + } + if (found && (iface->flags & IFF_UP)) + { + update = TRUE; + } + if (!iface->usable) + { /* ignore events for interfaces excluded by config */ + update = changed = FALSE; } } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); + + if (update && event && route_ifname) + { + queue_route_reinstall(this, route_ifname); + } + else + { + free(route_ifname); + } host->destroy(host); /* send an update to all IKE_SAs */ @@ -532,6 +1016,10 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h { return; } + else if (msg->rtm_flags & RTM_F_CLONED) + { /* ignore cached routes, seem to be created a lot for IPv6 */ + return; + } while (RTA_OK(rta, rtasize)) { @@ -551,20 +1039,26 @@ static void process_route(private_kernel_netlink_net_t *this, struct nlmsghdr *h } rta = RTA_NEXT(rta, rtasize); } + this->lock->read_lock(this->lock); + if (rta_oif && !is_interface_up_and_usable(this, rta_oif)) + { /* ignore route changes for interfaces that are ignored or down */ + this->lock->unlock(this->lock); + DESTROY_IF(host); + return; + } if (!host && rta_oif) { - host = get_interface_address(this, rta_oif, msg->rtm_family); + host = get_interface_address(this, rta_oif, msg->rtm_family, NULL); } - if (host) - { - this->mutex->lock(this->mutex); - if (!get_vip_refcount(this, host)) - { /* ignore routes added for virtual IPs */ - fire_roam_event(this, FALSE); - } - this->mutex->unlock(this->mutex); - host->destroy(host); + if (!host || is_known_vip(this, host)) + { /* ignore routes added for virtual IPs */ + this->lock->unlock(this->lock); + DESTROY_IF(host); + return; } + this->lock->unlock(this->lock); + fire_roam_event(this, FALSE); + host->destroy(host); } /** @@ -614,12 +1108,10 @@ static job_requeue_t receive_events(private_kernel_netlink_net_t *this) case RTM_NEWADDR: case RTM_DELADDR: process_addr(this, hdr, TRUE); - this->condvar->broadcast(this->condvar); break; case RTM_NEWLINK: case RTM_DELLINK: process_link(this, hdr, TRUE); - this->condvar->broadcast(this->condvar); break; case RTM_NEWROUTE: case RTM_DELROUTE: @@ -639,10 +1131,8 @@ static job_requeue_t receive_events(private_kernel_netlink_net_t *this) /** enumerator over addresses */ typedef struct { private_kernel_netlink_net_t* this; - /** whether to enumerate down interfaces */ - bool include_down_ifaces; - /** whether to enumerate virtual ip addresses */ - bool include_virtual_ips; + /** which addresses to enumerate */ + kernel_address_type_t which; } address_enumerator_t; /** @@ -650,7 +1140,7 @@ typedef struct { */ static void address_enumerator_destroy(address_enumerator_t *data) { - data->this->mutex->unlock(data->this->mutex); + data->this->lock->unlock(data->this->lock); free(data); } @@ -660,7 +1150,7 @@ static void address_enumerator_destroy(address_enumerator_t *data) static bool filter_addresses(address_enumerator_t *data, addr_entry_t** in, host_t** out) { - if (!data->include_virtual_ips && (*in)->virtual) + if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->refcount) { /* skip virtual interfaces added by us */ return FALSE; } @@ -689,7 +1179,15 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface, static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, iface_entry_t** out) { - if (!data->include_down_ifaces && !((*in)->flags & IFF_UP)) + if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable) + { /* skip interfaces excluded by config */ + return FALSE; + } + if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK)) + { /* ignore loopback devices */ + return FALSE; + } + if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP)) { /* skip interfaces not up */ return FALSE; } @@ -698,15 +1196,13 @@ static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, } METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, - private_kernel_netlink_net_t *this, - bool include_down_ifaces, bool include_virtual_ips) + private_kernel_netlink_net_t *this, kernel_address_type_t which) { address_enumerator_t *data = malloc_thing(address_enumerator_t); data->this = this; - data->include_down_ifaces = include_down_ifaces; - data->include_virtual_ips = include_virtual_ips; + data->which = which; - this->mutex->lock(this->mutex); + this->lock->read_lock(this->lock); return enumerator_create_nested( enumerator_create_filter( this->ifaces->create_enumerator(this->ifaces), @@ -715,47 +1211,40 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, (void*)address_enumerator_destroy); } -METHOD(kernel_net_t, get_interface_name, char*, - private_kernel_netlink_net_t *this, host_t* ip) +METHOD(kernel_net_t, get_interface_name, bool, + private_kernel_netlink_net_t *this, host_t* ip, char **name) { - enumerator_t *ifaces, *addrs; - iface_entry_t *iface; - addr_entry_t *addr; - char *name = NULL; - - DBG2(DBG_KNL, "getting interface name for %H", ip); + addr_map_entry_t *entry, lookup = { + .ip = ip, + }; - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) + if (ip->is_anyaddr(ip)) + { + return FALSE; + } + this->lock->read_lock(this->lock); + /* first try to find it on an up and usable interface */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match_up_and_usable); + if (entry) { - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, &addr)) - { - if (ip->ip_equals(ip, addr->ip)) - { - name = strdup(iface->ifname); - break; - } - } - addrs->destroy(addrs); if (name) { - break; + *name = strdup(entry->iface->ifname); + DBG2(DBG_KNL, "%H is on interface %s", ip, *name); } + this->lock->unlock(this->lock); + return TRUE; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - - if (name) - { - DBG2(DBG_KNL, "%H is on interface %s", ip, name); - } - else + /* maybe it is installed on an ignored interface */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match_up); + if (!entry) { - DBG2(DBG_KNL, "%H is not a local address", ip); + DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip); } - return name; + this->lock->unlock(this->lock); + return FALSE; } /** @@ -763,24 +1252,18 @@ METHOD(kernel_net_t, get_interface_name, char*, */ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) { - enumerator_t *ifaces; iface_entry_t *iface; int ifindex = 0; DBG2(DBG_KNL, "getting iface index for %s", name); - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) + this->lock->read_lock(this->lock); + if (this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name, + (void**)&iface, name) == SUCCESS) { - if (streq(name, iface->ifname)) - { - ifindex = iface->ifindex; - break; - } + ifindex = iface->ifindex; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); if (ifindex == 0) { @@ -789,29 +1272,6 @@ static int get_interface_index(private_kernel_netlink_net_t *this, char* name) return ifindex; } -/** - * Check if an interface with a given index is up - */ -static bool is_interface_up(private_kernel_netlink_net_t *this, int index) -{ - enumerator_t *ifaces; - iface_entry_t *iface; - /* default to TRUE for interface we do not monitor (e.g. lo) */ - bool up = TRUE; - - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) - { - if (iface->ifindex == index) - { - up = iface->flags & IFF_UP; - break; - } - } - ifaces->destroy(ifaces); - return up; -} - /** * check if an address (chunk) addr is in subnet (net with net_len net bits) */ @@ -848,6 +1308,94 @@ static bool addr_in_subnet(chunk_t addr, chunk_t net, int net_len) return TRUE; } +/** + * Store information about a route retrieved via RTNETLINK + */ +typedef struct { + chunk_t gtw; + chunk_t src; + chunk_t dst; + host_t *src_host; + u_int8_t dst_len; + u_int32_t table; + u_int32_t oif; +} rt_entry_t; + +/** + * Free a route entry + */ +static void rt_entry_destroy(rt_entry_t *this) +{ + DESTROY_IF(this->src_host); + free(this); +} + +/** + * Parse route received with RTM_NEWROUTE. The given rt_entry_t object will be + * reused if not NULL. + * + * Returned chunks point to internal data of the Netlink message. + */ +static rt_entry_t *parse_route(struct nlmsghdr *hdr, rt_entry_t *route) +{ + struct rtattr *rta; + struct rtmsg *msg; + size_t rtasize; + + msg = (struct rtmsg*)(NLMSG_DATA(hdr)); + rta = RTM_RTA(msg); + rtasize = RTM_PAYLOAD(hdr); + + if (route) + { + route->gtw = chunk_empty; + route->src = chunk_empty; + route->dst = chunk_empty; + route->dst_len = msg->rtm_dst_len; + route->table = msg->rtm_table; + route->oif = 0; + } + else + { + INIT(route, + .dst_len = msg->rtm_dst_len, + .table = msg->rtm_table, + ); + } + + while (RTA_OK(rta, rtasize)) + { + switch (rta->rta_type) + { + case RTA_PREFSRC: + route->src = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); + break; + case RTA_GATEWAY: + route->gtw = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); + break; + case RTA_DST: + route->dst = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); + break; + case RTA_OIF: + if (RTA_PAYLOAD(rta) == sizeof(route->oif)) + { + route->oif = *(u_int32_t*)RTA_DATA(rta); + } + break; +#ifdef HAVE_RTA_TABLE + case RTA_TABLE: + if (RTA_PAYLOAD(rta) == sizeof(route->table)) + { + route->table = *(u_int32_t*)RTA_DATA(rta); + } + break; +#endif /* HAVE_RTA_TABLE*/ + } + rta = RTA_NEXT(rta, rtasize); + } + return route; +} + /** * Get a route: If "nexthop", the nexthop is returned. source addr otherwise. */ @@ -859,22 +1407,21 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, struct rtmsg *msg; chunk_t chunk; size_t len; - int best = -1; + linked_list_t *routes; + rt_entry_t *route = NULL, *best = NULL; enumerator_t *enumerator; - host_t *src = NULL, *gtw = NULL; - - DBG2(DBG_KNL, "getting address to reach %H", dest); + host_t *addr = NULL; memset(&request, 0, sizeof(request)); hdr = (struct nlmsghdr*)request; hdr->nlmsg_flags = NLM_F_REQUEST; - if (dest->get_family(dest) == AF_INET) - { - /* We dump all addresses for IPv4, as we want to ignore IPsec specific - * routes installed by us. But the kernel does not return source - * addresses in a IPv6 dump, so fall back to get() for v6 routes. */ - hdr->nlmsg_flags |= NLM_F_ROOT | NLM_F_DUMP; + if (dest->get_family(dest) == AF_INET || this->rta_prefsrc_for_ipv6 || + this->routing_table) + { /* kernels prior to 3.0 do not support RTA_PREFSRC for IPv6 routes. + * as we want to ignore routes with virtual IPs we cannot use DUMP + * if these routes are not installed in a separate table */ + hdr->nlmsg_flags |= NLM_F_DUMP; } hdr->nlmsg_type = RTM_GETROUTE; hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -891,10 +1438,12 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS) { - DBG1(DBG_KNL, "getting address to %H failed", dest); + DBG2(DBG_KNL, "getting %s to reach %H failed", + nexthop ? "nexthop" : "address", dest); return NULL; } - this->mutex->lock(this->mutex); + routes = linked_list_create(); + this->lock->read_lock(this->lock); for (current = out; NLMSG_OK(current, len); current = NLMSG_NEXT(current, len)) @@ -905,132 +1454,53 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, break; case RTM_NEWROUTE: { - struct rtattr *rta; - size_t rtasize; - chunk_t rta_gtw, rta_src, rta_dst; - u_int32_t rta_oif = 0, rta_table; - host_t *new_src, *new_gtw; - bool cont = FALSE; + rt_entry_t *other; uintptr_t table; - rta_gtw = rta_src = rta_dst = chunk_empty; - msg = (struct rtmsg*)(NLMSG_DATA(current)); - rta = RTM_RTA(msg); - rtasize = RTM_PAYLOAD(current); - rta_table = msg->rtm_table; - while (RTA_OK(rta, rtasize)) - { - switch (rta->rta_type) - { - case RTA_PREFSRC: - rta_src = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); - break; - case RTA_GATEWAY: - rta_gtw = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); - break; - case RTA_DST: - rta_dst = chunk_create(RTA_DATA(rta), RTA_PAYLOAD(rta)); - break; - case RTA_OIF: - if (RTA_PAYLOAD(rta) == sizeof(rta_oif)) - { - rta_oif = *(u_int32_t*)RTA_DATA(rta); - } - break; -#ifdef HAVE_RTA_TABLE - case RTA_TABLE: - if (RTA_PAYLOAD(rta) == sizeof(rta_table)) - { - rta_table = *(u_int32_t*)RTA_DATA(rta); - } - break; -#endif /* HAVE_RTA_TABLE*/ - } - rta = RTA_NEXT(rta, rtasize); - } - if (msg->rtm_dst_len <= best) - { /* not better than a previous one */ - continue; - } - enumerator = this->rt_exclude->create_enumerator(this->rt_exclude); - while (enumerator->enumerate(enumerator, &table)) - { - if (table == rta_table) - { - cont = TRUE; - break; - } - } - enumerator->destroy(enumerator); - if (cont) - { + route = parse_route(current, route); + + table = (uintptr_t)route->table; + if (this->rt_exclude->find_first(this->rt_exclude, NULL, + (void**)&table) == SUCCESS) + { /* route is from an excluded routing table */ continue; } if (this->routing_table != 0 && - rta_table == this->routing_table) + route->table == this->routing_table) { /* route is from our own ipsec routing table */ continue; } - if (rta_oif && !is_interface_up(this, rta_oif)) + if (route->oif && !is_interface_up_and_usable(this, route->oif)) { /* interface is down */ continue; } - if (!addr_in_subnet(chunk, rta_dst, msg->rtm_dst_len)) + if (!addr_in_subnet(chunk, route->dst, route->dst_len)) { /* route destination does not contain dest */ continue; } - - if (nexthop) - { - /* nexthop lookup, return gateway if any */ - DESTROY_IF(gtw); - gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0); - best = msg->rtm_dst_len; - continue; - } - if (rta_src.ptr) - { /* got a source address */ - new_src = host_create_from_chunk(msg->rtm_family, rta_src, 0); - if (new_src) - { - if (get_vip_refcount(this, new_src)) - { /* skip source address if it is installed by us */ - new_src->destroy(new_src); - } - else - { - DESTROY_IF(src); - src = new_src; - best = msg->rtm_dst_len; - } - } - continue; - } - if (rta_oif) - { /* no src or gtw, but an interface. Get address from it. */ - new_src = get_interface_address(this, rta_oif, - msg->rtm_family); - if (new_src) - { - DESTROY_IF(src); - src = new_src; - best = msg->rtm_dst_len; + if (route->src.ptr) + { /* verify source address, if any */ + host_t *src = host_create_from_chunk(msg->rtm_family, + route->src, 0); + if (src && is_known_vip(this, src)) + { /* ignore routes installed by us */ + src->destroy(src); + continue; } - continue; + route->src_host = src; } - if (rta_gtw.ptr) - { /* no source, but a gateway. Lookup source to reach gtw. */ - new_gtw = host_create_from_chunk(msg->rtm_family, rta_gtw, 0); - new_src = get_route(this, new_gtw, FALSE, candidate); - new_gtw->destroy(new_gtw); - if (new_src) + /* insert route, sorted by decreasing network prefix */ + enumerator = routes->create_enumerator(routes); + while (enumerator->enumerate(enumerator, &other)) + { + if (route->dst_len > other->dst_len) { - DESTROY_IF(src); - src = new_src; - best = msg->rtm_dst_len; + break; } - continue; } + routes->insert_before(routes, enumerator, route); + enumerator->destroy(enumerator); + route = NULL; continue; } default: @@ -1038,18 +1508,111 @@ static host_t *get_route(private_kernel_netlink_net_t *this, host_t *dest, } break; } - free(out); - this->mutex->unlock(this->mutex); + if (route) + { + rt_entry_destroy(route); + } + + /* now we have a list of routes matching dest, sorted by net prefix. + * we will look for source addresses for these routes and select the one + * with the preferred source address, if possible */ + enumerator = routes->create_enumerator(routes); + while (enumerator->enumerate(enumerator, &route)) + { + if (route->src_host) + { /* got a source address with the route, if no preferred source + * is given or it matches we are done, as this is the best route */ + if (!candidate || candidate->ip_equals(candidate, route->src_host)) + { + best = route; + break; + } + else if (route->oif) + { /* no match yet, maybe it is assigned to the same interface */ + host_t *src = get_interface_address(this, route->oif, + msg->rtm_family, candidate); + if (src && src->ip_equals(src, candidate)) + { + route->src_host->destroy(route->src_host); + route->src_host = src; + best = route; + break; + } + DESTROY_IF(src); + } + /* no luck yet with the source address. if this is the best (first) + * route we store it as fallback in case we don't find a route with + * the preferred source */ + best = best ?: route; + continue; + } + if (route->oif) + { /* no src, but an interface - get address from it */ + route->src_host = get_interface_address(this, route->oif, + msg->rtm_family, candidate); + if (route->src_host) + { /* we handle this address the same as the one above */ + if (!candidate || + candidate->ip_equals(candidate, route->src_host)) + { + best = route; + break; + } + best = best ?: route; + continue; + } + } + if (route->gtw.ptr) + { /* no src, no iface, but a gateway - lookup src to reach gtw */ + host_t *gtw; + + gtw = host_create_from_chunk(msg->rtm_family, route->gtw, 0); + route->src_host = get_route(this, gtw, FALSE, candidate); + gtw->destroy(gtw); + if (route->src_host) + { /* more of the same */ + if (!candidate || + candidate->ip_equals(candidate, route->src_host)) + { + best = route; + break; + } + best = best ?: route; + } + } + } + enumerator->destroy(enumerator); if (nexthop) + { /* nexthop lookup, return gateway if any */ + if (best || routes->get_first(routes, (void**)&best) == SUCCESS) + { + addr = host_create_from_chunk(msg->rtm_family, best->gtw, 0); + } + addr = addr ?: dest->clone(dest); + } + else { - if (gtw) + if (best) { - return gtw; + addr = best->src_host->clone(best->src_host); } - return dest->clone(dest); } - return src; + this->lock->unlock(this->lock); + routes->destroy_function(routes, (void*)rt_entry_destroy); + free(out); + + if (addr) + { + DBG2(DBG_KNL, "using %H as %s to reach %H", addr, + nexthop ? "nexthop" : "address", dest); + } + else + { + DBG2(DBG_KNL, "no %s found to reach %H", + nexthop ? "nexthop" : "address", dest); + } + return addr; } METHOD(kernel_net_t, get_source_addr, host_t*, @@ -1059,9 +1622,9 @@ METHOD(kernel_net_t, get_source_addr, host_t*, } METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_netlink_net_t *this, host_t *dest) + private_kernel_netlink_net_t *this, host_t *dest, host_t *src) { - return get_route(this, dest, TRUE, NULL); + return get_route(this, dest, TRUE, src); } /** @@ -1100,87 +1663,109 @@ static status_t manage_ipaddr(private_kernel_netlink_net_t *this, int nlmsg_type METHOD(kernel_net_t, add_ip, status_t, private_kernel_netlink_net_t *this, host_t *virtual_ip, host_t *iface_ip) { - iface_entry_t *iface; - addr_entry_t *addr; - enumerator_t *addrs, *ifaces; - int ifindex; + addr_map_entry_t *entry, lookup = { + .ip = virtual_ip, + }; + iface_entry_t *iface = NULL; if (!this->install_virtual_ip) { /* disabled by config */ return SUCCESS; } - DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip); - - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) - { - bool iface_found = FALSE; - - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, &addr)) - { - if (iface_ip->ip_equals(iface_ip, addr->ip)) + this->lock->write_lock(this->lock); + /* the virtual IP might actually be installed as regular IP, in which case + * we don't track it as virtual IP */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match); + if (!entry) + { /* otherwise it might already be installed as virtual IP */ + entry = this->vips->get_match(this->vips, &lookup, + (void*)addr_map_entry_match); + if (entry) + { /* the vip we found can be in one of three states: 1) installed and + * ready, 2) just added by another thread, but not yet confirmed to + * be installed by the kernel, 3) just deleted, but not yet gone. + * Then while we wait below, several things could happen (as we + * release the lock). For instance, the interface could disappear, + * or the IP is finally deleted, and it reappears on a different + * interface. All these cases are handled by the call below. */ + while (!is_vip_installed_or_gone(this, virtual_ip, &entry)) { - iface_found = TRUE; + this->condvar->wait(this->condvar, this->lock); } - else if (virtual_ip->ip_equals(virtual_ip, addr->ip)) + if (entry) { - addr->refcount++; - DBG2(DBG_KNL, "virtual IP %H already installed on %s", - virtual_ip, iface->ifname); - addrs->destroy(addrs); - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - return SUCCESS; + entry->addr->refcount++; } } - addrs->destroy(addrs); - - if (iface_found) + } + if (entry) + { + DBG2(DBG_KNL, "virtual IP %H is already installed on %s", virtual_ip, + entry->iface->ifname); + this->lock->unlock(this->lock); + return SUCCESS; + } + /* try to find the target interface, either by config or via src ip */ + if (!this->install_virtual_ip_on || + this->ifaces->find_first(this->ifaces, (void*)iface_entry_by_name, + (void**)&iface, this->install_virtual_ip_on) != SUCCESS) + { + lookup.ip = iface_ip; + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match); + if (!entry) + { /* if we don't find the requested interface we just use the first */ + this->ifaces->get_first(this->ifaces, (void**)&iface); + } + else { - ifindex = iface->ifindex; - addr = malloc_thing(addr_entry_t); - addr->ip = virtual_ip->clone(virtual_ip); - addr->refcount = 0; - addr->virtual = TRUE; - addr->scope = RT_SCOPE_UNIVERSE; - iface->addrs->insert_last(iface->addrs, addr); - - if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, - ifindex, virtual_ip) == SUCCESS) - { - while (get_vip_refcount(this, virtual_ip) == 0) - { /* wait until address appears */ - this->condvar->wait(this->condvar, this->mutex); - } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + iface = entry->iface; + } + } + if (iface) + { + addr_entry_t *addr; + + INIT(addr, + .ip = virtual_ip->clone(virtual_ip), + .refcount = 1, + .scope = RT_SCOPE_UNIVERSE, + ); + iface->addrs->insert_last(iface->addrs, addr); + addr_map_entry_add(this->vips, addr, iface); + if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, + iface->ifindex, virtual_ip) == SUCCESS) + { + while (!is_vip_installed_or_gone(this, virtual_ip, &entry)) + { /* wait until address appears */ + this->condvar->wait(this->condvar, this->lock); + } + if (entry) + { /* we fail if the interface got deleted in the meantime */ + DBG2(DBG_KNL, "virtual IP %H installed on %s", virtual_ip, + entry->iface->ifname); + this->lock->unlock(this->lock); return SUCCESS; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip); - return FAILED; } + this->lock->unlock(this->lock); + DBG1(DBG_KNL, "adding virtual IP %H failed", virtual_ip); + return FAILED; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - - DBG1(DBG_KNL, "interface address %H not found, unable to install" - "virtual IP %H", iface_ip, virtual_ip); + this->lock->unlock(this->lock); + DBG1(DBG_KNL, "no interface available, unable to install virtual IP %H", + virtual_ip); return FAILED; } METHOD(kernel_net_t, del_ip, status_t, private_kernel_netlink_net_t *this, host_t *virtual_ip) { - iface_entry_t *iface; - addr_entry_t *addr; - enumerator_t *addrs, *ifaces; - status_t status; - int ifindex; + addr_map_entry_t *entry, lookup = { + .ip = virtual_ip, + }; if (!this->install_virtual_ip) { /* disabled by config */ @@ -1189,60 +1774,61 @@ METHOD(kernel_net_t, del_ip, status_t, DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip); - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) - { - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, &addr)) + this->lock->write_lock(this->lock); + entry = this->vips->get_match(this->vips, &lookup, + (void*)addr_map_entry_match); + if (!entry) + { /* we didn't install this IP as virtual IP */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match); + if (entry) { - if (virtual_ip->ip_equals(virtual_ip, addr->ip)) + DBG2(DBG_KNL, "not deleting existing IP %H on %s", virtual_ip, + entry->iface->ifname); + this->lock->unlock(this->lock); + return SUCCESS; + } + DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip); + this->lock->unlock(this->lock); + return FAILED; + } + if (entry->addr->refcount == 1) + { + status_t status; + + /* we set this flag so that threads calling add_ip will block and wait + * until the entry is gone, also so we can wait below */ + entry->addr->installed = FALSE; + status = manage_ipaddr(this, RTM_DELADDR, 0, entry->iface->ifindex, + virtual_ip); + if (status == SUCCESS) + { /* wait until the address is really gone */ + while (is_known_vip(this, virtual_ip)) { - ifindex = iface->ifindex; - if (addr->refcount == 1) - { - status = manage_ipaddr(this, RTM_DELADDR, 0, - ifindex, virtual_ip); - if (status == SUCCESS) - { /* wait until the address is really gone */ - while (get_vip_refcount(this, virtual_ip) > 0) - { - this->condvar->wait(this->condvar, this->mutex); - } - } - addrs->destroy(addrs); - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - return status; - } - else - { - addr->refcount--; - } - DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting", - virtual_ip); - addrs->destroy(addrs); - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - return SUCCESS; + this->condvar->wait(this->condvar, this->lock); } } - addrs->destroy(addrs); + this->lock->unlock(this->lock); + return status; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - - DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip); - return FAILED; + else + { + entry->addr->refcount--; + } + DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting", + virtual_ip); + this->lock->unlock(this->lock); + return SUCCESS; } /** * Manages source routes in the routing table. * By setting the appropriate nlmsg_type, the route gets added or removed. */ -static status_t manage_srcroute(private_kernel_netlink_net_t *this, int nlmsg_type, - int flags, chunk_t dst_net, u_int8_t prefixlen, - host_t *gateway, host_t *src_ip, char *if_name) +static status_t manage_srcroute(private_kernel_netlink_net_t *this, + int nlmsg_type, int flags, chunk_t dst_net, + u_int8_t prefixlen, host_t *gateway, + host_t *src_ip, char *if_name) { netlink_buf_t request; struct nlmsghdr *hdr; @@ -1306,16 +1892,56 @@ METHOD(kernel_net_t, add_route, status_t, private_kernel_netlink_net_t *this, chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) { - return manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, - dst_net, prefixlen, gateway, src_ip, if_name); + status_t status; + route_entry_t *found, route = { + .dst_net = dst_net, + .prefixlen = prefixlen, + .gateway = gateway, + .src_ip = src_ip, + .if_name = if_name, + }; + + this->routes_lock->lock(this->routes_lock); + found = this->routes->get(this->routes, &route); + if (found) + { + this->routes_lock->unlock(this->routes_lock); + return ALREADY_DONE; + } + found = route_entry_clone(&route); + this->routes->put(this->routes, found, found); + status = manage_srcroute(this, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, + dst_net, prefixlen, gateway, src_ip, if_name); + this->routes_lock->unlock(this->routes_lock); + return status; } METHOD(kernel_net_t, del_route, status_t, private_kernel_netlink_net_t *this, chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip, char *if_name) { - return manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen, - gateway, src_ip, if_name); + status_t status; + route_entry_t *found, route = { + .dst_net = dst_net, + .prefixlen = prefixlen, + .gateway = gateway, + .src_ip = src_ip, + .if_name = if_name, + }; + + this->routes_lock->lock(this->routes_lock); + found = this->routes->get(this->routes, &route); + if (!found) + { + this->routes_lock->unlock(this->routes_lock); + return NOT_FOUND; + } + this->routes->remove(this->routes, found); + route_entry_destroy(found); + status = manage_srcroute(this, RTM_DELROUTE, 0, dst_net, prefixlen, + gateway, src_ip, if_name); + this->routes_lock->unlock(this->routes_lock); + return status; } /** @@ -1331,7 +1957,7 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) iface_entry_t *iface; addr_entry_t *addr; - DBG1(DBG_KNL, "listening on interfaces:"); + DBG2(DBG_KNL, "known interfaces and IP addresses:"); memset(&request, 0, sizeof(request)); @@ -1389,23 +2015,23 @@ static status_t init_address_list(private_kernel_netlink_net_t *this) } free(out); - this->mutex->lock(this->mutex); + this->lock->read_lock(this->lock); ifaces = this->ifaces->create_enumerator(this->ifaces); while (ifaces->enumerate(ifaces, &iface)) { - if (iface->flags & IFF_UP) + if (iface_entry_up_and_usable(iface)) { - DBG1(DBG_KNL, " %s", iface->ifname); + DBG2(DBG_KNL, " %s", iface->ifname); addrs = iface->addrs->create_enumerator(iface->addrs); while (addrs->enumerate(addrs, (void**)&addr)) { - DBG1(DBG_KNL, " %H", addr->ip); + DBG2(DBG_KNL, " %H", addr->ip); } addrs->destroy(addrs); } } ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); return SUCCESS; } @@ -1443,9 +2069,59 @@ static status_t manage_rule(private_kernel_netlink_net_t *this, int nlmsg_type, return this->socket->send_ack(this->socket, hdr); } +/** + * check for kernel features (currently only via version number) + */ +static void check_kernel_features(private_kernel_netlink_net_t *this) +{ + struct utsname utsname; + int a, b, c; + + if (uname(&utsname) == 0) + { + switch(sscanf(utsname.release, "%d.%d.%d", &a, &b, &c)) + { + case 3: + if (a == 2) + { + DBG2(DBG_KNL, "detected Linux %d.%d.%d, no support for " + "RTA_PREFSRC for IPv6 routes", a, b, c); + break; + } + /* fall-through */ + case 2: + /* only 3.x+ uses two part version numbers */ + this->rta_prefsrc_for_ipv6 = TRUE; + break; + default: + break; + } + } +} + +/** + * Destroy an address to iface map + */ +static void addr_map_destroy(hashtable_t *map) +{ + enumerator_t *enumerator; + addr_map_entry_t *addr; + + enumerator = map->create_enumerator(map); + while (enumerator->enumerate(enumerator, NULL, (void**)&addr)) + { + free(addr); + } + enumerator->destroy(enumerator); + map->destroy(map); +} + METHOD(kernel_net_t, destroy, void, private_kernel_netlink_net_t *this) { + enumerator_t *enumerator; + route_entry_t *route; + if (this->routing_table) { manage_rule(this, RTM_DELRULE, AF_INET, this->routing_table, @@ -1453,19 +2129,34 @@ METHOD(kernel_net_t, destroy, void, manage_rule(this, RTM_DELRULE, AF_INET6, this->routing_table, this->routing_table_prio); } - if (this->job) - { - this->job->cancel(this->job); - } if (this->socket_events > 0) { close(this->socket_events); } + enumerator = this->routes->create_enumerator(this->routes); + while (enumerator->enumerate(enumerator, NULL, (void**)&route)) + { + manage_srcroute(this, RTM_DELROUTE, 0, route->dst_net, route->prefixlen, + route->gateway, route->src_ip, route->if_name); + route_entry_destroy(route); + } + enumerator->destroy(enumerator); + this->routes->destroy(this->routes); + this->routes_lock->destroy(this->routes_lock); DESTROY_IF(this->socket); + + net_changes_clear(this); + this->net_changes->destroy(this->net_changes); + this->net_changes_lock->destroy(this->net_changes_lock); + + addr_map_destroy(this->addrs); + addr_map_destroy(this->vips); + this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy); this->rt_exclude->destroy(this->rt_exclude); + this->roam_lock->destroy(this->roam_lock); this->condvar->destroy(this->condvar); - this->mutex->destroy(this->mutex); + this->lock->destroy(this->lock); free(this); } @@ -1475,8 +2166,8 @@ METHOD(kernel_net_t, destroy, void, kernel_netlink_net_t *kernel_netlink_net_create() { private_kernel_netlink_net_t *this; - struct sockaddr_nl addr; enumerator_t *enumerator; + bool register_for_events = TRUE; char *exclude; INIT(this, @@ -1495,9 +2186,22 @@ kernel_netlink_net_t *kernel_netlink_net_create() }, .socket = netlink_socket_create(NETLINK_ROUTE), .rt_exclude = linked_list_create(), + .routes = hashtable_create((hashtable_hash_t)route_entry_hash, + (hashtable_equals_t)route_entry_equals, 16), + .net_changes = hashtable_create( + (hashtable_hash_t)net_change_hash, + (hashtable_equals_t)net_change_equals, 16), + .addrs = hashtable_create( + (hashtable_hash_t)addr_map_entry_hash, + (hashtable_equals_t)addr_map_entry_equals, 16), + .vips = hashtable_create((hashtable_hash_t)addr_map_entry_hash, + (hashtable_equals_t)addr_map_entry_equals, 16), + .routes_lock = mutex_create(MUTEX_TYPE_DEFAULT), + .net_changes_lock = mutex_create(MUTEX_TYPE_DEFAULT), .ifaces = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_RECURSIVE), - .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .condvar = rwlock_condvar_create(), + .roam_lock = spinlock_create(), .routing_table = lib->settings->get_int(lib->settings, "%s.routing_table", ROUTING_TABLE, hydra->daemon), .routing_table_prio = lib->settings->get_int(lib->settings, @@ -1506,8 +2210,18 @@ kernel_netlink_net_t *kernel_netlink_net_create() "%s.process_route", TRUE, hydra->daemon), .install_virtual_ip = lib->settings->get_bool(lib->settings, "%s.install_virtual_ip", TRUE, hydra->daemon), + .install_virtual_ip_on = lib->settings->get_str(lib->settings, + "%s.install_virtual_ip_on", NULL, hydra->daemon), ); - timerclear(&this->last_roam); + timerclear(&this->last_route_reinstall); + timerclear(&this->next_roam); + + check_kernel_features(this); + + if (streq(hydra->daemon, "starter")) + { /* starter has no threads, so we do not register for kernel events */ + register_for_events = FALSE; + } exclude = lib->settings->get_str(lib->settings, "%s.ignore_routing_tables", NULL, hydra->daemon); @@ -1530,29 +2244,35 @@ kernel_netlink_net_t *kernel_netlink_net_create() enumerator->destroy(enumerator); } - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - - /* create and bind RT socket for events (address/interface/route changes) */ - this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (this->socket_events < 0) - { - DBG1(DBG_KNL, "unable to create RT event socket"); - destroy(this); - return NULL; - } - addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | - RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK; - if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr))) + if (register_for_events) { - DBG1(DBG_KNL, "unable to bind RT event socket"); - destroy(this); - return NULL; - } + struct sockaddr_nl addr; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + + /* create and bind RT socket for events (address/interface/route changes) */ + this->socket_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (this->socket_events < 0) + { + DBG1(DBG_KNL, "unable to create RT event socket"); + destroy(this); + return NULL; + } + addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | + RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE | RTMGRP_LINK; + if (bind(this->socket_events, (struct sockaddr*)&addr, sizeof(addr))) + { + DBG1(DBG_KNL, "unable to bind RT event socket"); + destroy(this); + return NULL; + } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)receive_events, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + } if (init_address_list(this) != SUCCESS) { diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c index dad3fb68e..285f6c8b2 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c @@ -206,6 +206,11 @@ METHOD(netlink_socket_t, netlink_send_ack, status_t, free(out); return ALREADY_DONE; } + if (-err->error == ESRCH) + { /* do not report missing entries */ + free(out); + return NOT_FOUND; + } DBG1(DBG_KNL, "received netlink error: %s (%d)", strerror(-err->error), -err->error); free(out); diff --git a/src/libhydra/plugins/kernel_pfkey/Makefile.in b/src/libhydra/plugins/kernel_pfkey/Makefile.in index 14c924b6f..aac85a4e6 100644 --- a/src/libhydra/plugins/kernel_pfkey/Makefile.in +++ b/src/libhydra/plugins/kernel_pfkey/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_kernel_pfkey_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_kernel_pfkey_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_kernel_pfkey_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index da10edffe..b099bc714 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil * @@ -51,6 +51,9 @@ #include #include #include +#ifdef __APPLE__ +#include +#endif #include "kernel_pfkey_ipsec.h" @@ -99,6 +102,20 @@ #define IPV6_IPSEC_POLICY 34 #endif +/* from linux/udp.h */ +#ifndef UDP_ENCAP +#define UDP_ENCAP 100 +#endif + +#ifndef UDP_ENCAP_ESPINUDP +#define UDP_ENCAP_ESPINUDP 2 +#endif + +/* this is not defined on some platforms */ +#ifndef SOL_UDP +#define SOL_UDP IPPROTO_UDP +#endif + /** default priority of installed policies */ #define PRIO_BASE 512 @@ -172,11 +189,6 @@ struct private_kernel_pfkey_ipsec_t */ bool install_routes; - /** - * job receiving PF_KEY events - */ - callback_job_t *job; - /** * mutex to lock access to the PF_KEY socket */ @@ -238,8 +250,8 @@ static void route_entry_destroy(route_entry_t *this) static bool route_entry_equals(route_entry_t *a, route_entry_t *b) { return a->if_name && b->if_name && streq(a->if_name, b->if_name) && - a->src_ip->equals(a->src_ip, b->src_ip) && - a->gateway->equals(a->gateway, b->gateway) && + a->src_ip->ip_equals(a->src_ip, b->src_ip) && + a->gateway->ip_equals(a->gateway, b->gateway) && chunk_equals(a->dst_net, b->dst_net) && a->prefixlen == b->prefixlen; } @@ -795,8 +807,22 @@ static kernel_algorithm_t compression_algs[] = { /** * Look up a kernel algorithm ID and its key size */ -static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) +static int lookup_algorithm(transform_type_t type, int ikev2) { + kernel_algorithm_t *list; + int alg = 0; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + list = encryption_algs; + break; + case INTEGRITY_ALGORITHM: + list = integrity_algs; + break; + default: + return 0; + } while (list->ikev2 != END_OF_LIST) { if (ikev2 == list->ikev2) @@ -805,18 +831,21 @@ static int lookup_algorithm(kernel_algorithm_t *list, int ikev2) } list++; } - return 0; + hydra->kernel_interface->lookup_algorithm(hydra->kernel_interface, ikev2, + type, &alg, NULL); + return alg; } /** - * Copy a host_t as sockaddr_t to the given memory location. Ports are - * reset to zero as per RFC 2367. + * Copy a host_t as sockaddr_t to the given memory location. * @return the number of bytes copied */ -static size_t hostcpy(void *dest, host_t *host) +static size_t hostcpy(void *dest, host_t *host, bool include_port) { sockaddr_t *addr = host->get_sockaddr(host), *dest_addr = dest; socklen_t *len = host->get_sockaddr_len(host); + u_int16_t port = htons(host->get_port(host)); + memcpy(dest, addr, *len); #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN dest_addr->sa_len = *len; @@ -826,13 +855,13 @@ static size_t hostcpy(void *dest, host_t *host) case AF_INET: { struct sockaddr_in *sin = dest; - sin->sin_port = 0; + sin->sin_port = include_port ? port : 0; break; } case AF_INET6: { struct sockaddr_in6 *sin6 = dest; - sin6->sin6_port = 0; + sin6->sin6_port = include_port ? port : 0; break; } } @@ -842,9 +871,9 @@ static size_t hostcpy(void *dest, host_t *host) /** * add a host behind an sadb_address extension */ -static void host2ext(host_t *host, struct sadb_address *ext) +static void host2ext(host_t *host, struct sadb_address *ext, bool include_port) { - size_t len = hostcpy(ext + 1, host); + size_t len = hostcpy(ext + 1, host, include_port); ext->sadb_address_len = PFKEY_LEN(sizeof(*ext) + len); } @@ -852,13 +881,13 @@ static void host2ext(host_t *host, struct sadb_address *ext) * add a host to the given sadb_msg */ static void add_addr_ext(struct sadb_msg *msg, host_t *host, u_int16_t type, - u_int8_t proto, u_int8_t prefixlen) + u_int8_t proto, u_int8_t prefixlen, bool include_port) { struct sadb_address *addr = (struct sadb_address*)PFKEY_EXT_ADD_NEXT(msg); addr->sadb_address_exttype = type; addr->sadb_address_proto = proto; addr->sadb_address_prefixlen = prefixlen; - host2ext(host, addr); + host2ext(host, addr, include_port); PFKEY_EXT_ADD(msg, addr); } @@ -1292,11 +1321,13 @@ static void process_mapping(private_kernel_pfkey_ipsec_t *this, { struct sockaddr_in *sin = (struct sockaddr_in*)sa; sin->sin_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port); + break; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa; sin6->sin6_port = htons(response.x_natt_dport->sadb_x_nat_t_port_port); + break; } default: break; @@ -1410,8 +1441,8 @@ METHOD(kernel_ipsec_t, get_spi, status_t, sa2->sadb_x_sa2_reqid = reqid; PFKEY_EXT_ADD(msg, sa2); - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); range = (struct sadb_spirange*)PFKEY_EXT_ADD_NEXT(msg); range->sadb_spirange_exttype = SADB_EXT_SPIRANGE; @@ -1497,8 +1528,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa->sadb_sa_len = PFKEY_LEN(len); sa->sadb_sa_spi = spi; sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32; - sa->sadb_sa_auth = lookup_algorithm(integrity_algs, int_alg); - sa->sadb_sa_encrypt = lookup_algorithm(encryption_algs, enc_alg); + sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg); + sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg); PFKEY_EXT_ADD(msg, sa); sa2 = (struct sadb_x_sa2*)PFKEY_EXT_ADD_NEXT(msg); @@ -1508,8 +1539,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t, sa2->sadb_x_sa2_reqid = reqid; PFKEY_EXT_ADD(msg, sa2); - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); lft = (struct sadb_lifetime*)PFKEY_EXT_ADD_NEXT(msg); lft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; @@ -1639,7 +1670,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t, /* the kernel wants a SADB_EXT_ADDRESS_SRC to be present even though * it is not used for anything. */ add_anyaddr_ext(msg, dst->get_family(dst), SADB_EXT_ADDRESS_SRC); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { @@ -1762,8 +1793,8 @@ METHOD(kernel_ipsec_t, query_sa, status_t, /* the Linux Kernel doesn't care for the src address, but other systems do * (e.g. FreeBSD) */ - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { @@ -1818,8 +1849,8 @@ METHOD(kernel_ipsec_t, del_sa, status_t, /* the Linux Kernel doesn't care for the src address, but other systems do * (e.g. FreeBSD) */ - add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0); - add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0); + add_addr_ext(msg, src, SADB_EXT_ADDRESS_SRC, 0, 0, FALSE); + add_addr_ext(msg, dst, SADB_EXT_ADDRESS_DST, 0, 0, FALSE); if (pfkey_send(this, msg, &out, &len) != SUCCESS) { @@ -1919,9 +1950,9 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; if (ipsec->cfg.mode == MODE_TUNNEL) { - len = hostcpy(req + 1, ipsec->src); + len = hostcpy(req + 1, ipsec->src, FALSE); req->sadb_x_ipsecrequest_len += len; - len = hostcpy((char*)(req + 1) + len, ipsec->dst); + len = hostcpy((char*)(req + 1) + len, ipsec->dst, FALSE); req->sadb_x_ipsecrequest_len += len; } @@ -1929,9 +1960,9 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, PFKEY_EXT_ADD(msg, pol); add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, - policy->src.mask); + policy->src.mask, TRUE); add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, - policy->dst.mask); + policy->dst.mask, TRUE); #ifdef __FreeBSD__ { /* on FreeBSD a lifetime has to be defined to be able to later query @@ -1989,23 +2020,26 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, if (policy->direction == POLICY_FWD && ipsec->cfg.mode != MODE_TRANSPORT && this->install_routes) { - route_entry_t *route = malloc_thing(route_entry_t); policy_sa_fwd_t *fwd = (policy_sa_fwd_t*)mapping; + route_entry_t *route; + + INIT(route, + .prefixlen = policy->src.mask, + ); if (hydra->kernel_interface->get_address_by_ts(hydra->kernel_interface, fwd->dst_ts, &route->src_ip) == SUCCESS) { /* get the nexthop to src (src as we are in POLICY_FWD).*/ route->gateway = hydra->kernel_interface->get_nexthop( - hydra->kernel_interface, ipsec->src); - /* install route via outgoing interface */ - route->if_name = hydra->kernel_interface->get_interface( - hydra->kernel_interface, ipsec->dst); + hydra->kernel_interface, ipsec->src, + ipsec->dst); route->dst_net = chunk_clone(policy->src.net->get_address( policy->src.net)); - route->prefixlen = policy->src.mask; - if (!route->if_name) + /* install route via outgoing interface */ + if (!hydra->kernel_interface->get_interface(hydra->kernel_interface, + ipsec->dst, &route->if_name)) { this->mutex->unlock(this->mutex); route_entry_destroy(route); @@ -2016,12 +2050,7 @@ static status_t add_policy_internal(private_kernel_pfkey_ipsec_t *this, { route_entry_t *old = policy->route; if (route_entry_equals(old, route)) - { /* keep previously installed route. since it might have - * still been removed by an address change, we install it - * again but ignore the result */ - hydra->kernel_interface->add_route(hydra->kernel_interface, - route->dst_net, route->prefixlen, route->gateway, - route->src_ip, route->if_name); + { this->mutex->unlock(this->mutex); route_entry_destroy(route); return SUCCESS; @@ -2200,9 +2229,9 @@ METHOD(kernel_ipsec_t, query_policy, status_t, PFKEY_EXT_ADD(msg, pol); add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, - policy->src.mask); + policy->src.mask, TRUE); add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, - policy->dst.mask); + policy->dst.mask, TRUE); this->mutex->unlock(this->mutex); @@ -2344,9 +2373,9 @@ METHOD(kernel_ipsec_t, del_policy, status_t, PFKEY_EXT_ADD(msg, pol); add_addr_ext(msg, policy->src.net, SADB_EXT_ADDRESS_SRC, policy->src.proto, - policy->src.mask); + policy->src.mask, TRUE); add_addr_ext(msg, policy->dst.net, SADB_EXT_ADDRESS_DST, policy->dst.proto, - policy->dst.mask); + policy->dst.mask, TRUE); if (policy->route) { @@ -2497,13 +2526,33 @@ METHOD(kernel_ipsec_t, bypass_socket, bool, return TRUE; } -METHOD(kernel_ipsec_t, destroy, void, - private_kernel_pfkey_ipsec_t *this) +METHOD(kernel_ipsec_t, enable_udp_decap, bool, + private_kernel_pfkey_ipsec_t *this, int fd, int family, u_int16_t port) { - if (this->job) +#ifndef __APPLE__ + int type = UDP_ENCAP_ESPINUDP; + + if (setsockopt(fd, SOL_UDP, UDP_ENCAP, &type, sizeof(type)) < 0) { - this->job->cancel(this->job); + DBG1(DBG_KNL, "unable to set UDP_ENCAP: %s", strerror(errno)); + return FALSE; } +#else /* __APPLE__ */ + if (sysctlbyname("net.inet.ipsec.esp_port", NULL, NULL, &port, + sizeof(port)) != 0) + { + DBG1(DBG_KNL, "could not set net.inet.ipsec.esp_port to %d: %s", + port, strerror(errno)); + return FALSE; + } +#endif /* __APPLE__ */ + + return TRUE; +} + +METHOD(kernel_ipsec_t, destroy, void, + private_kernel_pfkey_ipsec_t *this) +{ if (this->socket > 0) { close(this->socket); @@ -2528,6 +2577,7 @@ METHOD(kernel_ipsec_t, destroy, void, kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() { private_kernel_pfkey_ipsec_t *this; + bool register_for_events = TRUE; INIT(this, .public = { @@ -2544,6 +2594,7 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() .del_policy = _del_policy, .flush_policies = _flush_policies, .bypass_socket = _bypass_socket, + .enable_udp_decap = _enable_udp_decap, .destroy = _destroy, }, }, @@ -2561,6 +2612,10 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() { /* no routes for pluto, they are installed via updown script */ this->install_routes = FALSE; } + else if (streq(hydra->daemon, "starter")) + { /* starter has no threads, so we do not register for kernel events */ + register_for_events = FALSE; + } /* create a PF_KEY socket to communicate with the kernel */ this->socket = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); @@ -2571,27 +2626,31 @@ kernel_pfkey_ipsec_t *kernel_pfkey_ipsec_create() return NULL; } - /* create a PF_KEY socket for ACQUIRE & EXPIRE */ - this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - if (this->socket_events <= 0) + if (register_for_events) { - DBG1(DBG_KNL, "unable to create PF_KEY event socket"); - destroy(this); - return NULL; - } + /* create a PF_KEY socket for ACQUIRE & EXPIRE */ + this->socket_events = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); + if (this->socket_events <= 0) + { + DBG1(DBG_KNL, "unable to create PF_KEY event socket"); + destroy(this); + return NULL; + } - /* register the event socket */ - if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS || - register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS) - { - DBG1(DBG_KNL, "unable to register PF_KEY event socket"); - destroy(this); - return NULL; - } + /* register the event socket */ + if (register_pfkey_socket(this, SADB_SATYPE_ESP) != SUCCESS || + register_pfkey_socket(this, SADB_SATYPE_AH) != SUCCESS) + { + DBG1(DBG_KNL, "unable to register PF_KEY event socket"); + destroy(this); + return NULL; + } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)receive_events, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + } return &this->public; } diff --git a/src/libhydra/plugins/kernel_pfroute/Makefile.in b/src/libhydra/plugins/kernel_pfroute/Makefile.in index 1412db0ec..6fa2fc9c1 100644 --- a/src/libhydra/plugins/kernel_pfroute/Makefile.in +++ b/src/libhydra/plugins/kernel_pfroute/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_kernel_pfroute_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_kernel_pfroute_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_kernel_pfroute_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c index 5464568df..16a46bb56 100644 --- a/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c +++ b/src/libhydra/plugins/kernel_pfroute/kernel_pfroute_net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include @@ -85,6 +87,9 @@ struct iface_entry_t { /** list of addresses as host_t */ linked_list_t *addrs; + + /** TRUE if usable by config */ + bool usable; }; /** @@ -96,6 +101,73 @@ static void iface_entry_destroy(iface_entry_t *this) free(this); } +/** + * check if an interface is up + */ +static inline bool iface_entry_up(iface_entry_t *iface) +{ + return (iface->flags & IFF_UP) == IFF_UP; +} + +/** + * check if an interface is up and usable + */ +static inline bool iface_entry_up_and_usable(iface_entry_t *iface) +{ + return iface->usable && iface_entry_up(iface); +} + +typedef struct addr_map_entry_t addr_map_entry_t; + +/** + * Entry that maps an IP address to an interface entry + */ +struct addr_map_entry_t { + /** The IP address */ + host_t *ip; + + /** The interface this address is installed on */ + iface_entry_t *iface; +}; + +/** + * Hash a addr_map_entry_t object, all entries with the same IP address + * are stored in the same bucket + */ +static u_int addr_map_entry_hash(addr_map_entry_t *this) +{ + return chunk_hash(this->ip->get_address(this->ip)); +} + +/** + * Compare two addr_map_entry_t objects, two entries are equal if they are + * installed on the same interface + */ +static bool addr_map_entry_equals(addr_map_entry_t *a, addr_map_entry_t *b) +{ + return a->iface->ifindex == b->iface->ifindex && + a->ip->ip_equals(a->ip, b->ip); +} + +/** + * Used with get_match this finds an address entry if it is installed on + * an up and usable interface + */ +static bool addr_map_entry_match_up_and_usable(addr_map_entry_t *a, + addr_map_entry_t *b) +{ + return iface_entry_up_and_usable(b->iface) && + a->ip->ip_equals(a->ip, b->ip); +} + +/** + * Used with get_match this finds an address entry if it is installed on + * any active local interface + */ +static bool addr_map_entry_match_up(addr_map_entry_t *a, addr_map_entry_t *b) +{ + return iface_entry_up(b->iface) && a->ip->ip_equals(a->ip, b->ip); +} typedef struct private_kernel_pfroute_net_t private_kernel_pfroute_net_t; @@ -110,9 +182,9 @@ struct private_kernel_pfroute_net_t kernel_pfroute_net_t public; /** - * mutex to lock access to various lists + * lock to access lists and maps */ - mutex_t *mutex; + rwlock_t *lock; /** * Cached list of interfaces and their addresses (iface_entry_t) @@ -120,9 +192,9 @@ struct private_kernel_pfroute_net_t linked_list_t *ifaces; /** - * job receiving PF_ROUTE events + * Map for IP addresses to iface_entry_t objects (addr_map_entry_t) */ - callback_job_t *job; + hashtable_t *addrs; /** * mutex to lock access to the PF_ROUTE socket @@ -150,6 +222,48 @@ struct private_kernel_pfroute_net_t timeval_t last_roam; }; +/** + * Add an address map entry + */ +static void addr_map_entry_add(private_kernel_pfroute_net_t *this, + addr_entry_t *addr, iface_entry_t *iface) +{ + addr_map_entry_t *entry; + + if (addr->virtual) + { /* don't map virtual IPs */ + return; + } + + INIT(entry, + .ip = addr->ip, + .iface = iface, + ); + entry = this->addrs->put(this->addrs, entry, entry); + free(entry); +} + +/** + * Remove an address map entry (the argument order is a bit strange because + * it is also used with linked_list_t.invoke_function) + */ +static void addr_map_entry_remove(addr_entry_t *addr, iface_entry_t *iface, + private_kernel_pfroute_net_t *this) +{ + addr_map_entry_t *entry, lookup = { + .ip = addr->ip, + .iface = iface, + }; + + if (addr->virtual) + { /* these are never mapped, but this check avoid problems if a virtual IP + * equals a regular one */ + return; + } + entry = this->addrs->remove(this->addrs, &lookup); + free(entry); +} + /** * callback function that raises the delayed roam event */ @@ -219,7 +333,7 @@ static void process_addr(private_kernel_pfroute_net_t *this, return; } - this->mutex->lock(this->mutex); + this->lock->write_lock(this->lock); ifaces = this->ifaces->create_enumerator(this->ifaces); while (ifaces->enumerate(ifaces, &iface)) { @@ -234,12 +348,13 @@ static void process_addr(private_kernel_pfroute_net_t *this, if (ifa->ifam_type == RTM_DELADDR) { iface->addrs->remove_at(iface->addrs, addrs); - if (!addr->virtual) + if (!addr->virtual && iface->usable) { changed = TRUE; DBG1(DBG_KNL, "%H disappeared from %s", host, iface->ifname); } + addr_map_entry_remove(addr, iface, this); addr_entry_destroy(addr); } else if (ifa->ifam_type == RTM_NEWADDR && addr->virtual) @@ -258,10 +373,14 @@ static void process_addr(private_kernel_pfroute_net_t *this, addr->virtual = FALSE; addr->refcount = 1; iface->addrs->insert_last(iface->addrs, addr); - DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname); + addr_map_entry_add(this, addr, iface); + if (iface->usable) + { + DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname); + } } - if (changed && (iface->flags & IFF_UP)) + if (changed && iface_entry_up_and_usable(iface)) { roam = TRUE; } @@ -269,7 +388,7 @@ static void process_addr(private_kernel_pfroute_net_t *this, } } ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); host->destroy(host); if (roam) @@ -289,33 +408,31 @@ static void process_link(private_kernel_pfroute_net_t *this, iface_entry_t *iface; bool roam = FALSE; - if (msg->ifm_flags & IFF_LOOPBACK) - { /* ignore loopback interfaces */ - return; - } - - this->mutex->lock(this->mutex); + this->lock->write_lock(this->lock); enumerator = this->ifaces->create_enumerator(this->ifaces); while (enumerator->enumerate(enumerator, &iface)) { if (iface->ifindex == msg->ifm_index) { - if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP)) - { - roam = TRUE; - DBG1(DBG_KNL, "interface %s activated", iface->ifname); - } - else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP)) + if (iface->usable) { - roam = TRUE; - DBG1(DBG_KNL, "interface %s deactivated", iface->ifname); + if (!(iface->flags & IFF_UP) && (msg->ifm_flags & IFF_UP)) + { + roam = TRUE; + DBG1(DBG_KNL, "interface %s activated", iface->ifname); + } + else if ((iface->flags & IFF_UP) && !(msg->ifm_flags & IFF_UP)) + { + roam = TRUE; + DBG1(DBG_KNL, "interface %s deactivated", iface->ifname); + } } iface->flags = msg->ifm_flags; break; } } enumerator->destroy(enumerator); - this->mutex->unlock(this->mutex); + this->lock->unlock(this->lock); if (roam) { @@ -394,10 +511,8 @@ static job_requeue_t receive_events(private_kernel_pfroute_net_t *this) /** enumerator over addresses */ typedef struct { private_kernel_pfroute_net_t* this; - /** whether to enumerate down interfaces */ - bool include_down_ifaces; - /** whether to enumerate virtual ip addresses */ - bool include_virtual_ips; + /** which addresses to enumerate */ + kernel_address_type_t which; } address_enumerator_t; /** @@ -405,7 +520,7 @@ typedef struct { */ static void address_enumerator_destroy(address_enumerator_t *data) { - data->this->mutex->unlock(data->this->mutex); + data->this->lock->unlock(data->this->lock); free(data); } @@ -416,7 +531,7 @@ static bool filter_addresses(address_enumerator_t *data, addr_entry_t** in, host_t** out) { host_t *ip; - if (!data->include_virtual_ips && (*in)->virtual) + if (!(data->which & ADDR_TYPE_VIRTUAL) && (*in)->virtual) { /* skip virtual interfaces added by us */ return FALSE; } @@ -449,8 +564,16 @@ static enumerator_t *create_iface_enumerator(iface_entry_t *iface, static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, iface_entry_t** out) { - if (!data->include_down_ifaces && !((*in)->flags & IFF_UP)) - { /* skip interfaces not up */ + if (!(data->which & ADDR_TYPE_IGNORED) && !(*in)->usable) + { /* skip interfaces excluded by config */ + return FALSE; + } + if (!(data->which & ADDR_TYPE_LOOPBACK) && ((*in)->flags & IFF_LOOPBACK)) + { /* ignore loopback devices */ + return FALSE; + } + if (!(data->which & ADDR_TYPE_DOWN) && !((*in)->flags & IFF_UP)) + { /* skip interfaces not up */ return FALSE; } *out = *in; @@ -458,15 +581,13 @@ static bool filter_interfaces(address_enumerator_t *data, iface_entry_t** in, } METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, - private_kernel_pfroute_net_t *this, - bool include_down_ifaces, bool include_virtual_ips) + private_kernel_pfroute_net_t *this, kernel_address_type_t which) { address_enumerator_t *data = malloc_thing(address_enumerator_t); data->this = this; - data->include_down_ifaces = include_down_ifaces; - data->include_virtual_ips = include_virtual_ips; + data->which = which; - this->mutex->lock(this->mutex); + this->lock->read_lock(this->lock); return enumerator_create_nested( enumerator_create_filter( this->ifaces->create_enumerator(this->ifaces), @@ -475,47 +596,40 @@ METHOD(kernel_net_t, create_address_enumerator, enumerator_t*, (void*)address_enumerator_destroy); } -METHOD(kernel_net_t, get_interface_name, char*, - private_kernel_pfroute_net_t *this, host_t* ip) +METHOD(kernel_net_t, get_interface_name, bool, + private_kernel_pfroute_net_t *this, host_t* ip, char **name) { - enumerator_t *ifaces, *addrs; - iface_entry_t *iface; - addr_entry_t *addr; - char *name = NULL; - - DBG2(DBG_KNL, "getting interface name for %H", ip); + addr_map_entry_t *entry, lookup = { + .ip = ip, + }; - this->mutex->lock(this->mutex); - ifaces = this->ifaces->create_enumerator(this->ifaces); - while (ifaces->enumerate(ifaces, &iface)) + if (ip->is_anyaddr(ip)) + { + return FALSE; + } + this->lock->read_lock(this->lock); + /* first try to find it on an up and usable interface */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match_up_and_usable); + if (entry) { - addrs = iface->addrs->create_enumerator(iface->addrs); - while (addrs->enumerate(addrs, &addr)) - { - if (ip->ip_equals(ip, addr->ip)) - { - name = strdup(iface->ifname); - break; - } - } - addrs->destroy(addrs); if (name) { - break; + *name = strdup(entry->iface->ifname); + DBG2(DBG_KNL, "%H is on interface %s", ip, *name); } + this->lock->unlock(this->lock); + return TRUE; } - ifaces->destroy(ifaces); - this->mutex->unlock(this->mutex); - - if (name) - { - DBG2(DBG_KNL, "%H is on interface %s", ip, name); - } - else - { - DBG2(DBG_KNL, "%H is not a local address", ip); + /* maybe it is installed on an ignored interface */ + entry = this->addrs->get_match(this->addrs, &lookup, + (void*)addr_map_entry_match_up); + if (!entry) + { /* the address does not exist, is on a down interface */ + DBG2(DBG_KNL, "%H is not a local address or the interface is down", ip); } - return name; + this->lock->unlock(this->lock); + return FALSE; } METHOD(kernel_net_t, get_source_addr, host_t*, @@ -525,7 +639,7 @@ METHOD(kernel_net_t, get_source_addr, host_t*, } METHOD(kernel_net_t, get_nexthop, host_t*, - private_kernel_pfroute_net_t *this, host_t *dest) + private_kernel_pfroute_net_t *this, host_t *dest, host_t *src) { return NULL; } @@ -566,7 +680,7 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) addr_entry_t *addr; enumerator_t *ifaces, *addrs; - DBG1(DBG_KNL, "listening on interfaces:"); + DBG2(DBG_KNL, "known interfaces and IP addresses:"); if (getifaddrs(&ifap) < 0) { @@ -586,11 +700,6 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) case AF_INET: case AF_INET6: { - if (ifa->ifa_flags & IFF_LOOPBACK) - { /* ignore loopback interfaces */ - continue; - } - iface = NULL; ifaces = this->ifaces->create_enumerator(this->ifaces); while (ifaces->enumerate(ifaces, ¤t)) @@ -610,6 +719,8 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) iface->ifindex = if_nametoindex(ifa->ifa_name); iface->flags = ifa->ifa_flags; iface->addrs = linked_list_create(); + iface->usable = hydra->kernel_interface->is_interface_usable( + hydra->kernel_interface, ifa->ifa_name); this->ifaces->insert_last(this->ifaces, iface); } @@ -620,6 +731,7 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) addr->virtual = FALSE; addr->refcount = 1; iface->addrs->insert_last(iface->addrs, addr); + addr_map_entry_add(this, addr, iface); } } } @@ -629,13 +741,13 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) ifaces = this->ifaces->create_enumerator(this->ifaces); while (ifaces->enumerate(ifaces, &iface)) { - if (iface->flags & IFF_UP) + if (iface->usable && iface->flags & IFF_UP) { - DBG1(DBG_KNL, " %s", iface->ifname); + DBG2(DBG_KNL, " %s", iface->ifname); addrs = iface->addrs->create_enumerator(iface->addrs); while (addrs->enumerate(addrs, (void**)&addr)) { - DBG1(DBG_KNL, " %H", addr->ip); + DBG2(DBG_KNL, " %H", addr->ip); } addrs->destroy(addrs); } @@ -648,10 +760,9 @@ static status_t init_address_list(private_kernel_pfroute_net_t *this) METHOD(kernel_net_t, destroy, void, private_kernel_pfroute_net_t *this) { - if (this->job) - { - this->job->cancel(this->job); - } + enumerator_t *enumerator; + addr_entry_t *addr; + if (this->socket > 0) { close(this->socket); @@ -660,8 +771,15 @@ METHOD(kernel_net_t, destroy, void, { close(this->socket_events); } + enumerator = this->addrs->create_enumerator(this->addrs); + while (enumerator->enumerate(enumerator, NULL, (void**)&addr)) + { + free(addr); + } + enumerator->destroy(enumerator); + this->addrs->destroy(this->addrs); this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy); - this->mutex->destroy(this->mutex); + this->lock->destroy(this->lock); this->mutex_pfroute->destroy(this->mutex_pfroute); free(this); } @@ -672,6 +790,7 @@ METHOD(kernel_net_t, destroy, void, kernel_pfroute_net_t *kernel_pfroute_net_create() { private_kernel_pfroute_net_t *this; + bool register_for_events = TRUE; INIT(this, .public = { @@ -688,10 +807,18 @@ kernel_pfroute_net_t *kernel_pfroute_net_create() }, }, .ifaces = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .addrs = hashtable_create( + (hashtable_hash_t)addr_map_entry_hash, + (hashtable_equals_t)addr_map_entry_equals, 16), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .mutex_pfroute = mutex_create(MUTEX_TYPE_DEFAULT), ); + if (streq(hydra->daemon, "starter")) + { /* starter has no threads, so we do not register for kernel events */ + register_for_events = FALSE; + } + /* create a PF_ROUTE socket to communicate with the kernel */ this->socket = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); if (this->socket < 0) @@ -701,18 +828,22 @@ kernel_pfroute_net_t *kernel_pfroute_net_create() return NULL; } - /* create a PF_ROUTE socket to receive events */ - this->socket_events = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); - if (this->socket_events < 0) + if (register_for_events) { - DBG1(DBG_KNL, "unable to create PF_ROUTE event socket"); - destroy(this); - return NULL; - } + /* create a PF_ROUTE socket to receive events */ + this->socket_events = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); + if (this->socket_events < 0) + { + DBG1(DBG_KNL, "unable to create PF_ROUTE event socket"); + destroy(this); + return NULL; + } - this->job = callback_job_create_with_prio((callback_job_cb_t)receive_events, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)receive_events, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + } if (init_address_list(this) != SUCCESS) { diff --git a/src/libhydra/plugins/resolve/Makefile.in b/src/libhydra/plugins/resolve/Makefile.in index 41846ffe0..aed5ee19d 100644 --- a/src/libhydra/plugins/resolve/Makefile.in +++ b/src/libhydra/plugins/resolve/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_resolve_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_resolve_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_resolve_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libhydra/plugins/resolve/resolve_handler.c b/src/libhydra/plugins/resolve/resolve_handler.c index 011ebbaaf..0a3094fd7 100644 --- a/src/libhydra/plugins/resolve/resolve_handler.c +++ b/src/libhydra/plugins/resolve/resolve_handler.c @@ -150,6 +150,7 @@ static bool invoke_resolvconf(private_resolve_handler_t *this, bool install) { char cmd[128]; + bool success = TRUE; /* we use the nameserver's IP address as part of the interface name to * make them unique */ @@ -171,7 +172,8 @@ static bool invoke_resolvconf(private_resolve_handler_t *this, DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr); fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, server); - if (ferror(out) || pclose(out)) + success = !ferror(out); + if (pclose(out)) { return FALSE; } @@ -180,7 +182,7 @@ static bool invoke_resolvconf(private_resolve_handler_t *this, { ignore_result(system(cmd)); } - return TRUE; + return success; } METHOD(attribute_handler_t, handle, bool, @@ -267,46 +269,71 @@ METHOD(attribute_handler_t, release, void, typedef struct { /** implements enumerator_t interface */ enumerator_t public; - /** virtual IP we are requesting */ - host_t *vip; + /** request IPv4 DNS? */ + bool v4; + /** request IPv6 DNS? */ + bool v6; } attribute_enumerator_t; static bool attribute_enumerate(attribute_enumerator_t *this, configuration_attribute_type_t *type, chunk_t *data) { - switch (this->vip->get_family(this->vip)) + if (this->v4) { - case AF_INET: - *type = INTERNAL_IP4_DNS; - break; - case AF_INET6: - *type = INTERNAL_IP6_DNS; - break; - default: - return FALSE; + *type = INTERNAL_IP4_DNS; + *data = chunk_empty; + this->v4 = FALSE; + return TRUE; + } + if (this->v6) + { + *type = INTERNAL_IP6_DNS; + *data = chunk_empty; + this->v6 = FALSE; + return TRUE; } - *data = chunk_empty; - /* enumerate only once */ - this->public.enumerate = (void*)return_false; - return TRUE; + return FALSE; } -METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, - private_resolve_handler_t *this, identification_t *server, host_t *vip) +/** + * Check if a list has a host of given family + */ +static bool has_host_family(linked_list_t *list, int family) { - if (vip) + enumerator_t *enumerator; + host_t *host; + bool found = FALSE; + + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &host)) { - attribute_enumerator_t *enumerator; + if (host->get_family(host) == family) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); - enumerator = malloc_thing(attribute_enumerator_t); - enumerator->public.enumerate = (void*)attribute_enumerate; - enumerator->public.destroy = (void*)free; - enumerator->vip = vip; + return found; +} - return &enumerator->public; - } - return enumerator_create_empty(); +METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*, + private_resolve_handler_t *this, identification_t *server, + linked_list_t *vips) +{ + attribute_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)attribute_enumerate, + .destroy = (void*)free, + }, + .v4 = has_host_family(vips, AF_INET), + .v6 = has_host_family(vips, AF_INET6), + ); + return &enumerator->public; } METHOD(resolve_handler_t, destroy, void, diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index fae9fd662..e0e8f1017 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -13,8 +13,11 @@ libimcv_la_SOURCES = \ ietf/ietf_attr_pa_tnc_error.h ietf/ietf_attr_pa_tnc_error.c \ ietf/ietf_attr_port_filter.h ietf/ietf_attr_port_filter.c \ ietf/ietf_attr_product_info.h ietf/ietf_attr_product_info.c \ + ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \ + ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \ ita/ita_attr.h ita/ita_attr.c \ ita/ita_attr_command.h ita/ita_attr_command.c \ + ita/ita_attr_dummy.h ita/ita_attr_dummy.c \ pa_tnc/pa_tnc_attr.h \ pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \ pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c diff --git a/src/libimcv/Makefile.in b/src/libimcv/Makefile.in index 7e90a7aca..d1a1373af 100644 --- a/src/libimcv/Makefile.in +++ b/src/libimcv/Makefile.in @@ -53,6 +53,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -81,10 +82,11 @@ LTLIBRARIES = $(ipseclib_LTLIBRARIES) libimcv_la_DEPENDENCIES = $(top_builddir)/src/libtncif/libtncif.la am_libimcv_la_OBJECTS = imcv.lo imc_agent.lo imv_agent.lo ietf_attr.lo \ ietf_attr_pa_tnc_error.lo ietf_attr_port_filter.lo \ - ietf_attr_product_info.lo ita_attr.lo ita_attr_command.lo \ - pa_tnc_msg.lo pa_tnc_attr_manager.lo + ietf_attr_product_info.lo ietf_attr_attr_request.lo \ + ietf_attr_assess_result.lo ita_attr.lo ita_attr_command.lo \ + ita_attr_dummy.lo pa_tnc_msg.lo pa_tnc_attr_manager.lo libimcv_la_OBJECTS = $(am_libimcv_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -149,6 +151,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -243,11 +246,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -264,11 +270,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -284,6 +291,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -293,7 +301,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -332,8 +339,11 @@ libimcv_la_SOURCES = \ ietf/ietf_attr_pa_tnc_error.h ietf/ietf_attr_pa_tnc_error.c \ ietf/ietf_attr_port_filter.h ietf/ietf_attr_port_filter.c \ ietf/ietf_attr_product_info.h ietf/ietf_attr_product_info.c \ + ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \ + ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \ ita/ita_attr.h ita/ita_attr.c \ ita/ita_attr_command.h ita/ita_attr_command.c \ + ita/ita_attr_dummy.h ita/ita_attr_dummy.c \ pa_tnc/pa_tnc_attr.h \ pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \ pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c @@ -415,6 +425,8 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_assess_result.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_attr_request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_pa_tnc_error.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_port_filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attr_product_info.Plo@am__quote@ @@ -423,6 +435,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imv_agent.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ita_attr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ita_attr_command.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ita_attr_dummy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pa_tnc_attr_manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pa_tnc_msg.Plo@am__quote@ @@ -489,6 +502,20 @@ ietf_attr_product_info.lo: ietf/ietf_attr_product_info.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ietf_attr_product_info.lo `test -f 'ietf/ietf_attr_product_info.c' || echo '$(srcdir)/'`ietf/ietf_attr_product_info.c +ietf_attr_attr_request.lo: ietf/ietf_attr_attr_request.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ietf_attr_attr_request.lo -MD -MP -MF $(DEPDIR)/ietf_attr_attr_request.Tpo -c -o ietf_attr_attr_request.lo `test -f 'ietf/ietf_attr_attr_request.c' || echo '$(srcdir)/'`ietf/ietf_attr_attr_request.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ietf_attr_attr_request.Tpo $(DEPDIR)/ietf_attr_attr_request.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ietf/ietf_attr_attr_request.c' object='ietf_attr_attr_request.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ietf_attr_attr_request.lo `test -f 'ietf/ietf_attr_attr_request.c' || echo '$(srcdir)/'`ietf/ietf_attr_attr_request.c + +ietf_attr_assess_result.lo: ietf/ietf_attr_assess_result.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ietf_attr_assess_result.lo -MD -MP -MF $(DEPDIR)/ietf_attr_assess_result.Tpo -c -o ietf_attr_assess_result.lo `test -f 'ietf/ietf_attr_assess_result.c' || echo '$(srcdir)/'`ietf/ietf_attr_assess_result.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ietf_attr_assess_result.Tpo $(DEPDIR)/ietf_attr_assess_result.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ietf/ietf_attr_assess_result.c' object='ietf_attr_assess_result.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ietf_attr_assess_result.lo `test -f 'ietf/ietf_attr_assess_result.c' || echo '$(srcdir)/'`ietf/ietf_attr_assess_result.c + ita_attr.lo: ita/ita_attr.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ita_attr.lo -MD -MP -MF $(DEPDIR)/ita_attr.Tpo -c -o ita_attr.lo `test -f 'ita/ita_attr.c' || echo '$(srcdir)/'`ita/ita_attr.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ita_attr.Tpo $(DEPDIR)/ita_attr.Plo @@ -503,6 +530,13 @@ ita_attr_command.lo: ita/ita_attr_command.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ita_attr_command.lo `test -f 'ita/ita_attr_command.c' || echo '$(srcdir)/'`ita/ita_attr_command.c +ita_attr_dummy.lo: ita/ita_attr_dummy.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ita_attr_dummy.lo -MD -MP -MF $(DEPDIR)/ita_attr_dummy.Tpo -c -o ita_attr_dummy.lo `test -f 'ita/ita_attr_dummy.c' || echo '$(srcdir)/'`ita/ita_attr_dummy.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ita_attr_dummy.Tpo $(DEPDIR)/ita_attr_dummy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ita/ita_attr_dummy.c' object='ita_attr_dummy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ita_attr_dummy.lo `test -f 'ita/ita_attr_dummy.c' || echo '$(srcdir)/'`ita/ita_attr_dummy.c + pa_tnc_msg.lo: pa_tnc/pa_tnc_msg.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pa_tnc_msg.lo -MD -MP -MF $(DEPDIR)/pa_tnc_msg.Tpo -c -o pa_tnc_msg.lo `test -f 'pa_tnc/pa_tnc_msg.c' || echo '$(srcdir)/'`pa_tnc/pa_tnc_msg.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pa_tnc_msg.Tpo $(DEPDIR)/pa_tnc_msg.Plo diff --git a/src/libimcv/ietf/ietf_attr.c b/src/libimcv/ietf/ietf_attr.c index 89c6fc8db..fc89c5716 100644 --- a/src/libimcv/ietf/ietf_attr.c +++ b/src/libimcv/ietf/ietf_attr.c @@ -16,6 +16,8 @@ #include "ietf/ietf_attr_pa_tnc_error.h" #include "ietf/ietf_attr_port_filter.h" #include "ietf/ietf_attr_product_info.h" +#include "ietf/ietf_attr_attr_request.h" +#include "ietf/ietf_attr_assess_result.h" ENUM(ietf_attr_names, IETF_ATTR_TESTING, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED, "Testing", @@ -40,19 +42,21 @@ pa_tnc_attr_t* ietf_attr_create_from_data(u_int32_t type, chunk_t value) { switch (type) { + case IETF_ATTR_ATTRIBUTE_REQUEST: + return ietf_attr_attr_request_create_from_data(value); + case IETF_ATTR_PRODUCT_INFORMATION: + return ietf_attr_product_info_create_from_data(value); case IETF_ATTR_PORT_FILTER: return ietf_attr_port_filter_create_from_data(value); case IETF_ATTR_PA_TNC_ERROR: return ietf_attr_pa_tnc_error_create_from_data(value); - case IETF_ATTR_PRODUCT_INFORMATION: - return ietf_attr_product_info_create_from_data(value); + case IETF_ATTR_ASSESSMENT_RESULT: + return ietf_attr_assess_result_create_from_data(value); case IETF_ATTR_TESTING: - case IETF_ATTR_ATTRIBUTE_REQUEST: case IETF_ATTR_NUMERIC_VERSION: case IETF_ATTR_STRING_VERSION: case IETF_ATTR_OPERATIONAL_STATUS: case IETF_ATTR_INSTALLED_PACKAGES: - case IETF_ATTR_ASSESSMENT_RESULT: case IETF_ATTR_REMEDIATION_INSTRUCTIONS: case IETF_ATTR_FORWARDING_ENABLED: case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED: diff --git a/src/libimcv/ietf/ietf_attr_assess_result.c b/src/libimcv/ietf/ietf_attr_assess_result.c new file mode 100644 index 000000000..6893730bf --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_assess_result.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ietf_attr_assess_result.h" + +#include +#include +#include +#include + +typedef struct private_ietf_attr_assess_result_t private_ietf_attr_assess_result_t; + +/** + * PA-TNC Product Information type (see section 4.2.2 of RFC 5792) + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Assessment Result | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define ASSESS_RESULT_SIZE 4 + +/** + * Private data of an ietf_attr_assess_result_t object. + */ +struct private_ietf_attr_assess_result_t { + + /** + * Public members of ietf_attr_assess_result_t + */ + ietf_attr_assess_result_t public; + + /** + * Vendor-specific attribute type + */ + pen_type_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Assessment Result + */ + u_int32_t result; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_type, pen_type_t, + private_ietf_attr_assess_result_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_ietf_attr_assess_result_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_ietf_attr_assess_result_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_ietf_attr_assess_result_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_ietf_attr_assess_result_t *this) +{ + bio_writer_t *writer; + + if (this->value.ptr) + { + return; + } + + writer = bio_writer_create(ASSESS_RESULT_SIZE); + writer->write_uint32(writer, this->result); + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_ietf_attr_assess_result_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + + if (this->value.len < ASSESS_RESULT_SIZE) + { + DBG1(DBG_TNC, "insufficient data for IETF assessment result"); + *offset = 0; + return FAILED; + } + reader = bio_reader_create(this->value); + reader->read_uint32(reader, &this->result); + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_ietf_attr_assess_result_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_ietf_attr_assess_result_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(ietf_attr_assess_result_t, get_result, u_int32_t, + private_ietf_attr_assess_result_t *this) +{ + return this->result; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_assess_result_create(u_int32_t result) +{ + private_ietf_attr_assess_result_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_result = _get_result, + }, + .type = { PEN_IETF, IETF_ATTR_ASSESSMENT_RESULT }, + .result = result, + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_assess_result_create_from_data(chunk_t data) +{ + private_ietf_attr_assess_result_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_result = _get_result, + }, + .type = { PEN_IETF, IETF_ATTR_ASSESSMENT_RESULT }, + .value = chunk_clone(data), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + diff --git a/src/libimcv/ietf/ietf_attr_assess_result.h b/src/libimcv/ietf/ietf_attr_assess_result.h new file mode 100644 index 000000000..fab8bc3f0 --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_assess_result.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ietf_attr_assess_resultt ietf_attr_assess_result + * @{ @ingroup ietf + */ + +#ifndef IETF_ATTR_ASSESS_RESULT_H_ +#define IETF_ATTR_ASSESS_RESULT_H_ + +typedef struct ietf_attr_assess_result_t ietf_attr_assess_result_t; + +#include "ietf_attr.h" +#include "pa_tnc/pa_tnc_attr.h" + + +/** + * Class implementing the IETF PA-TNC Assessment Result attribute. + * + */ +struct ietf_attr_assess_result_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get the assessment result + * + * @return Assessment Result + */ + u_int32_t (*get_result)(ietf_attr_assess_result_t *this); + +}; + +/** + * Creates an ietf_attr_assess_result_t object + * + */ +pa_tnc_attr_t* ietf_attr_assess_result_create(u_int32_t result); + +/** + * Creates an ietf_attr_assess_result_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* ietf_attr_assess_result_create_from_data(chunk_t value); + +#endif /** IETF_ATTR_ASSESS_RESULT_H_ @}*/ diff --git a/src/libimcv/ietf/ietf_attr_attr_request.c b/src/libimcv/ietf/ietf_attr_attr_request.c new file mode 100644 index 000000000..c0dcd0983 --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_attr_request.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "imcv.h" +#include "ietf_attr_attr_request.h" + +#include +#include +#include +#include + +#include + +typedef struct private_ietf_attr_attr_request_t private_ietf_attr_attr_request_t; + +/** + * PA-TNC Attribute Request type (see section 4.2.1 of RFC 5792) + * + * 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | PA-TNC Attribute Vendor ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | PA-TNC Attribute Vendor ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | PA-TNC Attribute Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define ATTR_REQUEST_ENTRY_SIZE 8 + +/** + * Private data of an ietf_attr_attr_request_t object. + */ +struct private_ietf_attr_attr_request_t { + + /** + * Public members of ietf_attr_attr_request_t + */ + ietf_attr_attr_request_t public; + + /** + * Vendor-specific attribute type + */ + pen_type_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * List of requested attribute types + */ + linked_list_t *list; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_type, pen_type_t, + private_ietf_attr_attr_request_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_ietf_attr_attr_request_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_ietf_attr_attr_request_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_ietf_attr_attr_request_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_ietf_attr_attr_request_t *this) +{ + bio_writer_t *writer; + enumerator_t *enumerator; + pen_type_t *entry; + + if (this->value.ptr) + { + return; + } + writer = bio_writer_create(ATTR_REQUEST_ENTRY_SIZE * + this->list->get_count(this->list)); + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + writer->write_uint32(writer, entry->vendor_id); + writer->write_uint32(writer, entry->type); + } + enumerator->destroy(enumerator); + + this->value = chunk_clone(writer->get_buf(writer)); + writer->destroy(writer); +} + +METHOD(ietf_attr_attr_request_t, add, void, + private_ietf_attr_attr_request_t *this, pen_t vendor_id, u_int32_t type) +{ + pen_type_t *entry; + + entry = malloc_thing(pen_type_t); + entry->vendor_id = vendor_id; + entry->type = type; + this->list->insert_last(this->list, entry); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_ietf_attr_attr_request_t *this, u_int32_t *offset) +{ + bio_reader_t *reader; + enum_name_t *pa_attr_names; + pen_t vendor_id; + u_int32_t type; + u_int8_t reserved; + int count; + + count = this->value.len / ATTR_REQUEST_ENTRY_SIZE; + if (this->value.len != ATTR_REQUEST_ENTRY_SIZE * count) + { + DBG1(DBG_TNC, "incorrect attribute length for IETF attribute request"); + *offset = 0; + return FAILED; + } + + reader = bio_reader_create(this->value); + while (count--) + { + reader->read_uint8 (reader, &reserved); + reader->read_uint24(reader, &vendor_id); + reader->read_uint32(reader, &type); + + pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes, + vendor_id); + if (pa_attr_names) + { + DBG2(DBG_TNC, " 0x%06x/0x%08x '%N/%N'", vendor_id, type, + pen_names, vendor_id, pa_attr_names, type); + } + else + { + DBG2(DBG_TNC, " 0x%06x/0x%08x '%N'", vendor_id, type, + pen_names, vendor_id); + } + add(this, vendor_id, type); + } + reader->destroy(reader); + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_ietf_attr_attr_request_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_ietf_attr_attr_request_t *this) +{ + if (ref_put(&this->ref)) + { + this->list->destroy_function(this->list, free); + free(this->value.ptr); + free(this); + } +} + +METHOD(ietf_attr_attr_request_t, create_enumerator, enumerator_t*, + private_ietf_attr_attr_request_t *this) +{ + return this->list->create_enumerator(this->list); +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_attr_request_create(pen_t vendor_id, u_int32_t type) +{ + private_ietf_attr_attr_request_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .add = _add, + .create_enumerator = _create_enumerator, + }, + .type = { PEN_IETF, IETF_ATTR_ATTRIBUTE_REQUEST }, + .list = linked_list_create(), + .ref = 1, + ); + add(this, vendor_id, type); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ietf_attr_attr_request_create_from_data(chunk_t data) +{ + private_ietf_attr_attr_request_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .add = _add, + .create_enumerator = _create_enumerator, + }, + .type = { PEN_IETF,IETF_ATTR_ATTRIBUTE_REQUEST }, + .value = chunk_clone(data), + .list = linked_list_create(), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + diff --git a/src/libimcv/ietf/ietf_attr_attr_request.h b/src/libimcv/ietf/ietf_attr_attr_request.h new file mode 100644 index 000000000..22c5be0a0 --- /dev/null +++ b/src/libimcv/ietf/ietf_attr_attr_request.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ietf_attr_attr_requestt ietf_attr_attr_request + * @{ @ingroup ietf + */ + +#ifndef IETF_ATTR_ATTR_REQUEST_H_ +#define IETF_ATTR_ATTR_REQUEST_H_ + +typedef struct ietf_attr_attr_request_t ietf_attr_attr_request_t; + +#include "ietf_attr.h" +#include "pa_tnc/pa_tnc_attr.h" + + +/** + * Class implementing the IETF PA-TNC Attribute Request attribute. + * + */ +struct ietf_attr_attr_request_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Adds another attribute type to the attribute request + * + * @param vendor_id Attribute Vendor ID + * @param type Attribute Type + */ + void (*add)(ietf_attr_attr_request_t *this, pen_t vendor_id, u_int32_t type); + + /** + * Creates an enumerator over all attribute types contained + * in the attribute request + * + * @return Attribute Type enumerator returns (vendor ID, type) + */ + enumerator_t* (*create_enumerator)(ietf_attr_attr_request_t *this); +}; + +/** + * Creates an ietf_attr_attr_request_t object + * + */ +pa_tnc_attr_t* ietf_attr_attr_request_create(pen_t vendor_id, u_int32_t type); + +/** + * Creates an ietf_attr_attr_request_t object from received data + * + * @param value unparsed attribute value + */ +pa_tnc_attr_t* ietf_attr_attr_request_create_from_data(chunk_t value); + +#endif /** IETF_ATTR_ATTR_REQUEST_H_ @}*/ diff --git a/src/libimcv/ietf/ietf_attr_pa_tnc_error.c b/src/libimcv/ietf/ietf_attr_pa_tnc_error.c index 6daee1a77..46f5d6716 100644 --- a/src/libimcv/ietf/ietf_attr_pa_tnc_error.c +++ b/src/libimcv/ietf/ietf_attr_pa_tnc_error.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -107,14 +108,9 @@ struct private_ietf_attr_pa_tnc_error_t { ietf_attr_pa_tnc_error_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -127,14 +123,9 @@ struct private_ietf_attr_pa_tnc_error_t { bool noskip_flag; /** - * Error code vendor ID - */ - pen_t error_vendor_id; - - /** - * Error code + * Vendor-specific error code */ - u_int32_t error_code; + pen_type_t error_code; /** * First 8 bytes of erroneous PA-TNC message @@ -157,13 +148,7 @@ struct private_ietf_attr_pa_tnc_error_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_ietf_attr_pa_tnc_error_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_ietf_attr_pa_tnc_error_t *this) { return this->type; @@ -192,15 +177,19 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE); writer->write_uint8 (writer, PA_ERROR_RESERVED); - writer->write_uint24(writer, this->error_vendor_id); - writer->write_uint32(writer, this->error_code); + writer->write_uint24(writer, this->error_code.vendor_id); + writer->write_uint32(writer, this->error_code.type); writer->write_data (writer, this->msg_info); - if (this->error_vendor_id == PEN_IETF) + if (this->error_code.vendor_id == PEN_IETF) { - switch (this->error_code) + switch (this->error_code.type) { case PA_ERROR_INVALID_PARAMETER: writer->write_uint32(writer, this->error_offset); @@ -235,10 +224,10 @@ METHOD(pa_tnc_attr_t, process, status_t, } reader = bio_reader_create(this->value); reader->read_uint8 (reader, &reserved); - reader->read_uint24(reader, &this->error_vendor_id); - reader->read_uint32(reader, &this->error_code); + reader->read_uint24(reader, &this->error_code.vendor_id); + reader->read_uint32(reader, &this->error_code.type); - if (this->error_vendor_id == PEN_IETF) + if (this->error_code.vendor_id == PEN_IETF) { if (!reader->read_data(reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info)) { @@ -249,7 +238,7 @@ METHOD(pa_tnc_attr_t, process, status_t, } this->msg_info = chunk_clone(this->msg_info); - switch (this->error_code) + switch (this->error_code.type) { case PA_ERROR_INVALID_PARAMETER: if (!reader->read_uint32(reader, &this->error_offset)) @@ -305,13 +294,7 @@ METHOD(pa_tnc_attr_t, destroy, void, } } -METHOD(ietf_attr_pa_tnc_error_t, get_error_vendor_id, pen_t, - private_ietf_attr_pa_tnc_error_t *this) -{ - return this->error_vendor_id; -} - -METHOD(ietf_attr_pa_tnc_error_t, get_error_code, u_int32_t, +METHOD(ietf_attr_pa_tnc_error_t, get_error_code, pen_type_t, private_ietf_attr_pa_tnc_error_t *this) { return this->error_code; @@ -344,13 +327,12 @@ METHOD(ietf_attr_pa_tnc_error_t, get_offset, u_int32_t, /** * Described in header. */ -pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id, - u_int32_t error_code, +pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_type_t error_code, chunk_t msg_info) { private_ietf_attr_pa_tnc_error_t *this; - if (vendor_id == PEN_IETF) + if (error_code.vendor_id == PEN_IETF) { msg_info.len = PA_ERROR_MSG_INFO_SIZE; } @@ -362,7 +344,6 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -372,16 +353,13 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id, .get_ref = _get_ref, .destroy = _destroy, }, - .get_vendor_id = _get_error_vendor_id, .get_error_code = _get_error_code, .get_msg_info = _get_msg_info, .get_attr_info = _get_attr_info, .set_attr_info = _set_attr_info, .get_offset = _get_offset, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PA_TNC_ERROR, - .error_vendor_id = vendor_id, + .type = { PEN_IETF, IETF_ATTR_PA_TNC_ERROR }, .error_code = error_code, .msg_info = chunk_clone(msg_info), .ref = 1, @@ -393,8 +371,7 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id, /** * Described in header. */ -pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id, - u_int32_t error_code, +pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_type_t error_code, chunk_t msg_info, u_int32_t error_offset) { @@ -406,7 +383,6 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -416,16 +392,13 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id, .get_ref = _get_ref, .destroy = _destroy, }, - .get_vendor_id = _get_error_vendor_id, .get_error_code = _get_error_code, .get_msg_info = _get_msg_info, .get_attr_info = _get_attr_info, .set_attr_info = _set_attr_info, .get_offset = _get_offset, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PA_TNC_ERROR, - .error_vendor_id = vendor_id, + .type = { PEN_IETF, IETF_ATTR_PA_TNC_ERROR }, .error_code = error_code, .msg_info = chunk_clone(msg_info), .error_offset = error_offset, @@ -445,7 +418,6 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .build = _build, @@ -453,15 +425,13 @@ pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data) .get_ref = _get_ref, .destroy = _destroy, }, - .get_vendor_id = _get_error_vendor_id, .get_error_code = _get_error_code, .get_msg_info = _get_msg_info, .get_attr_info = _get_attr_info, .set_attr_info = _set_attr_info, .get_offset = _get_offset, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PA_TNC_ERROR, + .type = { PEN_IETF, IETF_ATTR_PA_TNC_ERROR }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libimcv/ietf/ietf_attr_pa_tnc_error.h b/src/libimcv/ietf/ietf_attr_pa_tnc_error.h index 945e06c62..d28c524aa 100644 --- a/src/libimcv/ietf/ietf_attr_pa_tnc_error.h +++ b/src/libimcv/ietf/ietf_attr_pa_tnc_error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -62,11 +62,11 @@ struct ietf_attr_pa_tnc_error_t { pen_t (*get_vendor_id)(ietf_attr_pa_tnc_error_t *this); /** - * Get PA-TNC error code + * Get Vendor-specific PA-TNC error code * * @return error code */ - pa_tnc_error_code_t (*get_error_code)(ietf_attr_pa_tnc_error_t *this); + pen_type_t (*get_error_code)(ietf_attr_pa_tnc_error_t *this); /** * Get first 8 bytes of erroneous PA-TNC message @@ -101,26 +101,22 @@ struct ietf_attr_pa_tnc_error_t { /** * Creates an ietf_attr_pa_tnc_error_t object from an error code * - * @param vendor_id PA-TNC error code vendor ID - * @param error_code PA-TNC error code + * @param error_code Vendor-specific PA-TNC error code * @param header PA-TNC message header (first 8 bytes) * */ -pa_tnc_attr_t* ietf_attr_pa_tnc_error_create(pen_t vendor_id, - u_int32_t error_code, +pa_tnc_attr_t* ietf_attr_pa_tnc_error_create(pen_type_t error_code, chunk_t header); /** * Creates an ietf_attr_pa_tnc_error_t object from an error code with offset * - * @param vendor_id PA-TNC error code vendor ID - * @param error_code PA-TNC error code + * @param error_code Vendor-specifica PA-TNC error code * @param header PA-TNC message header (first 8 bytes) * @param error_offset PA-TNC error offset in bytes * */ -pa_tnc_attr_t* ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id, - u_int32_t error_code, +pa_tnc_attr_t* ietf_attr_pa_tnc_error_create_with_offset(pen_type_t error_code, chunk_t header, u_int32_t error_offset); diff --git a/src/libimcv/ietf/ietf_attr_port_filter.c b/src/libimcv/ietf/ietf_attr_port_filter.c index b53019657..5ea52256b 100644 --- a/src/libimcv/ietf/ietf_attr_port_filter.c +++ b/src/libimcv/ietf/ietf_attr_port_filter.c @@ -58,14 +58,9 @@ struct private_ietf_attr_port_filter_t { ietf_attr_port_filter_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -88,13 +83,7 @@ struct private_ietf_attr_port_filter_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_ietf_attr_port_filter_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_ietf_attr_port_filter_t *this) { return this->type; @@ -125,6 +114,10 @@ METHOD(pa_tnc_attr_t, build, void, enumerator_t *enumerator; port_entry_t *entry; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(this->ports->get_count(this->ports) * PORT_FILTER_ENTRY_SIZE); @@ -232,7 +225,6 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -245,8 +237,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create(void) .add_port = _add_port, .create_port_enumerator = _create_port_enumerator, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PORT_FILTER, + .type = { PEN_IETF, IETF_ATTR_PORT_FILTER }, .ports = linked_list_create(), .ref = 1, ); @@ -264,7 +255,6 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .build = _build, @@ -275,8 +265,7 @@ pa_tnc_attr_t *ietf_attr_port_filter_create_from_data(chunk_t data) .add_port = _add_port, .create_port_enumerator = _create_port_enumerator, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PORT_FILTER, + .type = {PEN_IETF, IETF_ATTR_PORT_FILTER }, .value = chunk_clone(data), .ports = linked_list_create(), .ref = 1, diff --git a/src/libimcv/ietf/ietf_attr_product_info.c b/src/libimcv/ietf/ietf_attr_product_info.c index 548793547..dcc0e0294 100644 --- a/src/libimcv/ietf/ietf_attr_product_info.c +++ b/src/libimcv/ietf/ietf_attr_product_info.c @@ -46,14 +46,9 @@ struct private_ietf_attr_product_info_t { ietf_attr_product_info_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -86,13 +81,7 @@ struct private_ietf_attr_product_info_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_ietf_attr_product_info_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_ietf_attr_product_info_t *this) { return this->type; @@ -122,6 +111,10 @@ METHOD(pa_tnc_attr_t, build, void, bio_writer_t *writer; chunk_t product_name; + if (this->value.ptr) + { + return; + } product_name = chunk_create(this->product_name, strlen(this->product_name)); writer = bio_writer_create(PRODUCT_INFO_MIN_SIZE); @@ -201,7 +194,6 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -213,8 +205,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create(pen_t vendor_id, u_int16_t id, }, .get_info = _get_info, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PRODUCT_INFORMATION, + .type = { PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION }, .product_vendor_id = vendor_id, .product_id = id, .product_name = strdup(name), @@ -234,7 +225,6 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .build = _build, @@ -244,8 +234,7 @@ pa_tnc_attr_t *ietf_attr_product_info_create_from_data(chunk_t data) }, .get_info = _get_info, }, - .vendor_id = PEN_IETF, - .type = IETF_ATTR_PRODUCT_INFORMATION, + .type = { PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libimcv/imc/imc_agent.c b/src/libimcv/imc/imc_agent.c index de2f959a4..8d1e70716 100644 --- a/src/libimcv/imc/imc_agent.c +++ b/src/libimcv/imc/imc_agent.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -18,7 +19,6 @@ #include #include -#include #include typedef struct private_imc_agent_t private_imc_agent_t; @@ -333,12 +333,31 @@ static char* get_str_attribute(private_imc_agent_t *this, TNC_ConnectionID id, return NULL; } +/** + * Read an UInt32 attribute + */ +static u_int32_t get_uint_attribute(private_imc_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[4]; + + if (this->get_attribute && + this->get_attribute(this->id, id, attribute_id, 4, buf, &len) == + TNC_RESULT_SUCCESS && len == 4) + { + return untoh32(buf); + } + return 0; + } + METHOD(imc_agent_t, create_state, TNC_Result, private_imc_agent_t *this, imc_state_t *state) { TNC_ConnectionID conn_id; char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; + u_int32_t max_msg_len; conn_id = state->get_connection_id(state); if (find_connection(this, conn_id)) @@ -357,14 +376,18 @@ METHOD(imc_agent_t, create_state, TNC_Result, tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION); t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL); t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION); + max_msg_len = get_uint_attribute(this, conn_id, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE); state->set_flags(state, has_long, has_excl); + state->set_max_msg_len(state, max_msg_len); + + DBG2(DBG_IMC, "IMC %u \"%s\" created a state for %s %s Connection ID %u: " + "%slong %sexcl %ssoh", this->id, this->name, + tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id, + has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-"); + DBG2(DBG_IMC, " over %s %s with maximum PA-TNC message size of %u bytes", + t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len); - DBG2(DBG_IMC, "IMC %u \"%s\" created a state for Connection ID %u: " - "%s %s with %slong %sexcl %ssoh over %s %s", - this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?", - tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-", - has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?"); free(tnccs_p); free(tnccs_v); free(t_p); @@ -453,11 +476,17 @@ METHOD(imc_agent_t, get_state, bool, METHOD(imc_agent_t, send_message, TNC_Result, private_imc_agent_t *this, TNC_ConnectionID connection_id, bool excl, - TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, chunk_t msg) + TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, linked_list_t *attr_list) { TNC_MessageType type; TNC_UInt32 msg_flags; + TNC_Result result = TNC_RESULT_FATAL; imc_state_t *state; + pa_tnc_attr_t *attr; + pa_tnc_msg_t *pa_tnc_msg; + chunk_t msg; + enumerator_t *enumerator; + bool attr_added; state = find_connection(this, connection_id); if (!state) @@ -467,26 +496,70 @@ METHOD(imc_agent_t, send_message, TNC_Result, return TNC_RESULT_FATAL; } - if (state->has_long(state) && this->send_message_long) + while (attr_list->get_count(attr_list)) { - if (!src_imc_id) + pa_tnc_msg = pa_tnc_msg_create(state->get_max_msg_len(state)); + attr_added = FALSE; + + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) { - src_imc_id = this->id; + if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr)) + { + attr_added = TRUE; + } + else + { + if (attr_added) + { + break; + } + else + { + DBG1(DBG_IMC, "PA-TNC attribute too large to send, deleted"); + attr->destroy(attr); + } + } + attr_list->remove_at(attr_list, enumerator); } - msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + enumerator->destroy(enumerator); - return this->send_message_long(src_imc_id, connection_id, msg_flags, - msg.ptr, msg.len, this->vendor_id, - this->subtype, dst_imv_id); - } - if (this->send_message) - { - type = (this->vendor_id << 8) | this->subtype; + /* build and send the PA-TNC message via the IF-IMC interface */ + if (!pa_tnc_msg->build(pa_tnc_msg)) + { + pa_tnc_msg->destroy(pa_tnc_msg); + return TNC_RESULT_FATAL; + } + msg = pa_tnc_msg->get_encoding(pa_tnc_msg); + + if (state->has_long(state) && this->send_message_long) + { + if (!src_imc_id) + { + src_imc_id = this->id; + } + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + + result = this->send_message_long(src_imc_id, connection_id, + msg_flags, msg.ptr, msg.len, this->vendor_id, + this->subtype, dst_imv_id); + } + else if (this->send_message) + { + type = (this->vendor_id << 8) | this->subtype; - return this->send_message(this->id, connection_id, msg.ptr, msg.len, - type); + result = this->send_message(this->id, connection_id, msg.ptr, + msg.len, type); + } + + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result != TNC_RESULT_SUCCESS) + { + break; + } } - return TNC_RESULT_FATAL; + return result; } METHOD(imc_agent_t, receive_message, TNC_Result, @@ -494,11 +567,11 @@ METHOD(imc_agent_t, receive_message, TNC_Result, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, pa_tnc_msg_t **pa_tnc_msg) { - pa_tnc_msg_t *pa_msg, *error_msg; + pa_tnc_msg_t *pa_msg; pa_tnc_attr_t *error_attr; + linked_list_t *error_attr_list; enumerator_t *enumerator; - TNC_MessageType msg_type; - TNC_UInt32 msg_flags, src_imc_id, dst_imv_id; + TNC_UInt32 src_imc_id, dst_imv_id; TNC_ConnectionID connection_id; TNC_Result result; @@ -534,51 +607,24 @@ METHOD(imc_agent_t, receive_message, TNC_Result, *pa_tnc_msg = pa_msg; break; case VERIFY_ERROR: - /* build error message */ - error_msg = pa_tnc_msg_create(); + /* extract and copy by refence all error attributes */ + error_attr_list = linked_list_create(); + enumerator = pa_msg->create_error_enumerator(pa_msg); while (enumerator->enumerate(enumerator, &error_attr)) { - error_msg->add_attribute(error_msg, - error_attr->get_ref(error_attr)); + error_attr_list->insert_last(error_attr_list, + error_attr->get_ref(error_attr)); } enumerator->destroy(enumerator); - error_msg->build(error_msg); - - /* send error message */ - if (state->has_long(state) && this->send_message_long) - { - if (state->has_excl(state)) - { - msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE; - dst_imv_id = src_imv_id; - } - else - { - msg_flags = 0; - dst_imv_id = TNC_IMVID_ANY; - } - src_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? this->id - : dst_imc_id; - result = this->send_message_long(src_imc_id, connection_id, - msg_flags, msg.ptr, msg.len, msg_vid, - msg_subtype, dst_imv_id); - } - else if (this->send_message) - { - msg_type = (msg_vid << 8) | msg_subtype; + src_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? this->id : dst_imc_id; + dst_imv_id = state->has_excl(state) ? src_imv_id : TNC_IMVID_ANY; - result = this->send_message(this->id, connection_id, - msg.ptr, msg.len, msg_type); - } - else - { - result = TNC_RESULT_FATAL; - } + result = send_message(this, connection_id, state->has_excl(state), + src_imc_id, dst_imv_id, error_attr_list); - /* clean up */ - error_msg->destroy(error_msg); + error_attr_list->destroy(error_attr_list); pa_msg->destroy(pa_msg); return result; case FAILED: diff --git a/src/libimcv/imc/imc_agent.h b/src/libimcv/imc/imc_agent.h index d1fef4d8d..e87450aa6 100644 --- a/src/libimcv/imc/imc_agent.h +++ b/src/libimcv/imc/imc_agent.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,6 +27,7 @@ #include #include +#include #include @@ -104,13 +106,13 @@ struct imc_agent_t { * @param excl exclusive flag * @param src_imc_id IMC ID to be set as source * @param dst_imv_id IMV ID to be set as destination - * @param msg message to send + * @param attr_list list of PA-TNC attributes to send * @return TNC result code */ TNC_Result (*send_message)(imc_agent_t *this, TNC_ConnectionID connection_id, bool excl, TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, - chunk_t msg); + linked_list_t *attr_list); /** * Call when a PA-TNC message was received diff --git a/src/libimcv/imc/imc_state.h b/src/libimcv/imc/imc_state.h index f1b0358c9..c34441f0f 100644 --- a/src/libimcv/imc/imc_state.h +++ b/src/libimcv/imc/imc_state.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -22,6 +23,8 @@ #define IMC_STATE_H_ #include +#include +#include #include @@ -33,8 +36,7 @@ typedef struct imc_state_t imc_state_t; struct imc_state_t { /** - * Get the TNCS connection I -D attached to the state + * Get the TNCS connection ID attached to the state * * @return TNCS connection ID of the state */ @@ -63,6 +65,20 @@ D attached to the state */ void (*set_flags)(imc_state_t *this, bool has_long, bool has_excl); + /** + * Set the maximum size of a PA-TNC message for this TNCCS connection + * + * @max_msg_len maximum size of a PA-TNC message + */ + void (*set_max_msg_len)(imc_state_t *this, u_int32_t max_msg_len); + + /** + * Get the maximum size of a PA-TNC message for this TNCCS connection + * + * @return maximum size of a PA-TNC message + */ + u_int32_t (*get_max_msg_len)(imc_state_t *this); + /** * Change the connection state * @@ -70,6 +86,25 @@ D attached to the state */ void (*change_state)(imc_state_t *this, TNC_ConnectionState new_state); + /** + * Set the Assessment/Evaluation Result + * + * @param id IMC ID + * @param result Assessment/Evaluation Result + */ + void (*set_result)(imc_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result); + + /** + * Get the Assessment/Evaluation Result + * + * @param id IMC ID + * @param result Assessment/Evaluation Result + * @return TRUE if result is known + */ + bool (*get_result)(imc_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result); + /** * Destroys an imc_state_t object */ diff --git a/src/libimcv/imcv.c b/src/libimcv/imcv.c index a8c0af47b..b84548f9b 100644 --- a/src/libimcv/imcv.c +++ b/src/libimcv/imcv.c @@ -108,7 +108,7 @@ bool libimcv_init(void) } if (!lib->plugins->load(lib->plugins, NULL, - "sha1 sha2 random gmp pubkey x509")) + "sha1 sha2 random nonce gmp pubkey x509")) { library_deinit(); return FALSE; diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index 56131c547..fa04e0237 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,11 +15,11 @@ #include "imcv.h" #include "imv_agent.h" +#include "ietf/ietf_attr_assess_result.h" #include #include -#include #include typedef struct private_imv_agent_t private_imv_agent_t; @@ -48,6 +49,11 @@ struct private_imv_agent_t { */ TNC_MessageSubtype subtype; + /** + * Maximum PA-TNC Message size + */ + size_t max_msg_len; + /** * ID of IMV as assigned by TNCS */ @@ -351,12 +357,31 @@ static char* get_str_attribute(private_imv_agent_t *this, TNC_ConnectionID id, return NULL; } +/** + * Read an UInt32 attribute + */ +static u_int32_t get_uint_attribute(private_imv_agent_t *this, TNC_ConnectionID id, + TNC_AttributeID attribute_id) +{ + TNC_UInt32 len; + char buf[4]; + + if (this->get_attribute && + this->get_attribute(this->id, id, attribute_id, 4, buf, &len) == + TNC_RESULT_SUCCESS && len == 4) + { + return untoh32(buf); + } + return 0; + } + METHOD(imv_agent_t, create_state, TNC_Result, private_imv_agent_t *this, imv_state_t *state) { TNC_ConnectionID conn_id; char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; + u_int32_t max_msg_len; conn_id = state->get_connection_id(state); if (find_connection(this, conn_id)) @@ -371,18 +396,22 @@ METHOD(imv_agent_t, create_state, TNC_Result, has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES); has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE); has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH); - tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); + tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL); tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION); t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL); t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION); + max_msg_len = get_uint_attribute(this, conn_id, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE); state->set_flags(state, has_long, has_excl); + state->set_max_msg_len(state, max_msg_len); + + DBG2(DBG_IMV, "IMV %u \"%s\" created a state for %s %s Connection ID %u: " + "%slong %sexcl %ssoh", this->id, this->name, + tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id, + has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-"); + DBG2(DBG_IMV, " over %s %s with maximum PA-TNC message size of %u bytes", + t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len); - DBG2(DBG_IMV, "IMV %u \"%s\" created a state for Connection ID %u: " - "%s %s with %slong %sexcl %ssoh over %s %s", - this->id, this->name, conn_id, tnccs_p ? tnccs_p:"?", - tnccs_v ? tnccs_v:"?", has_long ? "+":"-", has_excl ? "+":"-", - has_soh ? "+":"-", t_p ? t_p:"?", t_v ? t_v :"?"); free(tnccs_p); free(tnccs_v); free(t_p); @@ -449,7 +478,7 @@ METHOD(imv_agent_t, change_state, TNC_Result, DBG1(DBG_IMV, "IMV %u \"%s\" was notified of unknown state %u " "for Connection ID %u", this->id, this->name, new_state, connection_id); - return TNC_RESULT_INVALID_PARAMETER; + return TNC_RESULT_INVALID_PARAMETER; } return TNC_RESULT_SUCCESS; } @@ -470,11 +499,17 @@ METHOD(imv_agent_t, get_state, bool, METHOD(imv_agent_t, send_message, TNC_Result, private_imv_agent_t *this, TNC_ConnectionID connection_id, bool excl, - TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, chunk_t msg) + TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, linked_list_t *attr_list) { TNC_MessageType type; TNC_UInt32 msg_flags; + TNC_Result result = TNC_RESULT_FATAL; imv_state_t *state; + pa_tnc_attr_t *attr; + pa_tnc_msg_t *pa_tnc_msg; + chunk_t msg; + enumerator_t *enumerator; + bool attr_added; state = find_connection(this, connection_id); if (!state) @@ -484,26 +519,70 @@ METHOD(imv_agent_t, send_message, TNC_Result, return TNC_RESULT_FATAL; } - if (state->has_long(state) && this->send_message_long) + while (attr_list->get_count(attr_list)) { - if (!src_imv_id) + pa_tnc_msg = pa_tnc_msg_create(this->max_msg_len); + attr_added = FALSE; + + enumerator = attr_list->create_enumerator(attr_list); + while (enumerator->enumerate(enumerator, &attr)) + { + if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr)) + { + attr_added = TRUE; + } + else + { + if (attr_added) + { + break; + } + else + { + DBG1(DBG_IMV, "PA-TNC attribute too large to send, deleted"); + attr->destroy(attr); + } + } + attr_list->remove_at(attr_list, enumerator); + } + enumerator->destroy(enumerator); + + /* build and send the PA-TNC message via the IF-IMV interface */ + if (!pa_tnc_msg->build(pa_tnc_msg)) { - src_imv_id = this->id; + pa_tnc_msg->destroy(pa_tnc_msg); + return TNC_RESULT_FATAL; } - msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; + msg = pa_tnc_msg->get_encoding(pa_tnc_msg); - return this->send_message_long(src_imv_id, connection_id, msg_flags, - msg.ptr, msg.len, this->vendor_id, - this->subtype, dst_imc_id); - } - if (this->send_message) - { - type = (this->vendor_id << 8) | this->subtype; + if (state->has_long(state) && this->send_message_long) + { + if (!src_imv_id) + { + src_imv_id = this->id; + } + msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0; - return this->send_message(this->id, connection_id, msg.ptr, msg.len, - type); + result = this->send_message_long(src_imv_id, connection_id, + msg_flags, msg.ptr, msg.len, this->vendor_id, + this->subtype, dst_imc_id); + } + else if (this->send_message) + { + type = (this->vendor_id << 8) | this->subtype; + + result = this->send_message(this->id, connection_id, msg.ptr, + msg.len, type); + } + + pa_tnc_msg->destroy(pa_tnc_msg); + + if (result != TNC_RESULT_SUCCESS) + { + break; + } } - return TNC_RESULT_FATAL; + return result; } METHOD(imv_agent_t, set_recommendation, TNC_Result, @@ -530,11 +609,11 @@ METHOD(imv_agent_t, receive_message, TNC_Result, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, pa_tnc_msg_t **pa_tnc_msg) { - pa_tnc_msg_t *pa_msg, *error_msg; + pa_tnc_msg_t *pa_msg; pa_tnc_attr_t *error_attr; + linked_list_t *error_attr_list; enumerator_t *enumerator; - TNC_MessageType msg_type; - TNC_UInt32 msg_flags, src_imv_id, dst_imc_id; + TNC_UInt32 src_imv_id, dst_imc_id; TNC_ConnectionID connection_id; TNC_Result result; @@ -570,53 +649,24 @@ METHOD(imv_agent_t, receive_message, TNC_Result, *pa_tnc_msg = pa_msg; break; case VERIFY_ERROR: - /* build error message */ - error_msg = pa_tnc_msg_create(); + /* extract and copy by refence all error attributes */ + error_attr_list = linked_list_create(); + enumerator = pa_msg->create_error_enumerator(pa_msg); while (enumerator->enumerate(enumerator, &error_attr)) { - error_msg->add_attribute(error_msg, - error_attr->get_ref(error_attr)); + error_attr_list->insert_last(error_attr_list, + error_attr->get_ref(error_attr)); } enumerator->destroy(enumerator); - error_msg->build(error_msg); - /* send error message */ - msg = error_msg->get_encoding(error_msg); + src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id : dst_imv_id; + dst_imc_id = state->has_excl(state) ? src_imc_id : TNC_IMCID_ANY; - if (state->has_long(state) && this->send_message_long) - { - if (state->has_excl(state)) - { - msg_flags = TNC_MESSAGE_FLAGS_EXCLUSIVE; - dst_imc_id = src_imc_id; - } - else - { - msg_flags = 0; - dst_imc_id = TNC_IMCID_ANY; - } - src_imv_id = (dst_imv_id == TNC_IMVID_ANY) ? this->id - : dst_imv_id; - - result = this->send_message_long(src_imv_id, connection_id, - msg_flags, msg.ptr, msg.len, msg_vid, - msg_subtype, dst_imc_id); - } - else if (this->send_message) - { - msg_type = (msg_vid << 8) | msg_subtype; + result = send_message(this, connection_id, state->has_excl(state), + src_imv_id, dst_imc_id, error_attr_list); - result = this->send_message(this->id, connection_id, - msg.ptr, msg.len, msg_type); - } - else - { - result = TNC_RESULT_FATAL; - } - - /* clean up */ - error_msg->destroy(error_msg); + error_attr_list->destroy(error_attr_list); pa_msg->destroy(pa_msg); return result; case FAILED: @@ -633,9 +683,13 @@ METHOD(imv_agent_t, receive_message, TNC_Result, } METHOD(imv_agent_t, provide_recommendation, TNC_Result, - private_imv_agent_t *this, TNC_ConnectionID connection_id) + private_imv_agent_t *this, TNC_ConnectionID connection_id, + TNC_UInt32 dst_imc_id) { imv_state_t *state; + linked_list_t *attr_list; + pa_tnc_attr_t *attr; + TNC_Result result; TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; TNC_UInt32 lang_len; @@ -651,7 +705,6 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, } state->get_recommendation(state, &rec, &eval); - /* send a reason string if action recommendation is not allow */ if (rec != TNC_IMV_ACTION_RECOMMENDATION_ALLOW) { @@ -663,8 +716,8 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, lang_len <= BUF_LEN) { pref_lang.len = lang_len; - DBG2(DBG_IMV, "preferred language is '%.*s'", - pref_lang.len, pref_lang.ptr); + DBG2(DBG_IMV, "preferred language is '%.*s'", (int)pref_lang.len, + pref_lang.ptr); } /* find a reason string for the preferred or default language and set it */ @@ -680,7 +733,21 @@ METHOD(imv_agent_t, provide_recommendation, TNC_Result, reason_lang.len, reason_lang.ptr); } } - + + /* Send an IETF Assessment Result attribute if enabled */ + if (lib->settings->get_bool(lib->settings, "libimcv.assessment_result", TRUE)) + { + attr = ietf_attr_assess_result_create(eval); + attr_list = linked_list_create(); + attr_list->insert_last(attr_list, attr); + result = send_message(this, connection_id, FALSE, this->id, dst_imc_id, + attr_list); + attr_list->destroy(attr_list); + if (result != TNC_RESULT_SUCCESS) + { + return result; + } + } return this->provide_recommendation(this->id, connection_id, rec, eval); } @@ -777,6 +844,7 @@ imv_agent_t *imv_agent_create(const char *name, .name = name, .vendor_id = vendor_id, .subtype = subtype, + .max_msg_len = 65490, .id = id, .additional_ids = linked_list_create(), .connections = linked_list_create(), diff --git a/src/libimcv/imv/imv_agent.h b/src/libimcv/imv/imv_agent.h index de70f3bc1..34ac3c109 100644 --- a/src/libimcv/imv/imv_agent.h +++ b/src/libimcv/imv/imv_agent.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,6 +27,7 @@ #include #include +#include #include @@ -104,13 +106,13 @@ struct imv_agent_t { * @param excl exclusive flag * @param src_imv_id IMV ID to be set as source * @param dst_imc_id IMD ID to be set as destination - * @param msg message to send + * @param attr_list list of PA-TNC attributes to send * @return TNC result code */ TNC_Result (*send_message)(imv_agent_t *this, TNC_ConnectionID connection_id, bool excl, TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, - chunk_t msg); + linked_list_t *attr_list); /** * Call when a PA-TNC message was received @@ -149,10 +151,12 @@ struct imv_agent_t { * Deliver IMV Action Recommendation and IMV Evaluation Result to the TNCS * * @param connection_id network connection ID assigned by TNCS + * @param dst_imc_id IMD ID to be set as destination * @return TNC result code */ TNC_Result (*provide_recommendation)(imv_agent_t *this, - TNC_ConnectionID connection_id); + TNC_ConnectionID connection_id, + TNC_UInt32 dst_imc_id); /** * Reserve additional IMV IDs from TNCS diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index 9e7a29a9f..1b0845b84 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -62,6 +63,20 @@ struct imv_state_t { */ void (*set_flags)(imv_state_t *this, bool has_long, bool has_excl); + /** + * Set the maximum size of a PA-TNC message for this TNCCS connection + * + * @max_msg_len maximum size of a PA-TNC message + */ + void (*set_max_msg_len)(imv_state_t *this, u_int32_t max_msg_len); + + /** + * Get the maximum size of a PA-TNC message for this TNCCS connection + * + * @return maximum size of a PA-TNC message + */ + u_int32_t (*get_max_msg_len)(imv_state_t *this); + /** * Change the connection state * diff --git a/src/libimcv/ita/ita_attr.c b/src/libimcv/ita/ita_attr.c index ec23c11ea..0ea799c3a 100644 --- a/src/libimcv/ita/ita_attr.c +++ b/src/libimcv/ita/ita_attr.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,9 +15,11 @@ #include "ita_attr.h" #include "ita/ita_attr_command.h" +#include "ita/ita_attr_dummy.h" -ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_COMMAND, +ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DUMMY, "Command", + "Dummy", ); /** @@ -29,6 +31,8 @@ pa_tnc_attr_t* ita_attr_create_from_data(u_int32_t type, chunk_t value) { case ITA_ATTR_COMMAND: return ita_attr_command_create_from_data(value); + case ITA_ATTR_DUMMY: + return ita_attr_dummy_create_from_data(value); default: return NULL; } diff --git a/src/libimcv/ita/ita_attr.h b/src/libimcv/ita/ita_attr.h index 82debdd1e..3baf0e3b8 100644 --- a/src/libimcv/ita/ita_attr.h +++ b/src/libimcv/ita/ita_attr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ typedef enum ita_attr_t ita_attr_t; */ enum ita_attr_t { ITA_ATTR_COMMAND = 1, + ITA_ATTR_DUMMY = 2, }; /** diff --git a/src/libimcv/ita/ita_attr_command.c b/src/libimcv/ita/ita_attr_command.c index 5c1577a7c..d43e4777b 100644 --- a/src/libimcv/ita/ita_attr_command.c +++ b/src/libimcv/ita/ita_attr_command.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -32,14 +33,9 @@ struct private_ita_attr_command_t { ita_attr_command_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -62,13 +58,7 @@ struct private_ita_attr_command_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_ita_attr_command_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_ita_attr_command_t *this) { return this->type; @@ -95,6 +85,10 @@ METHOD(pa_tnc_attr_t, set_noskip_flag,void, METHOD(pa_tnc_attr_t, build, void, private_ita_attr_command_t *this) { + if (this->value.ptr) + { + return; + } this->value = chunk_create(this->command, strlen(this->command)); this->value = chunk_clone(this->value); } @@ -143,7 +137,6 @@ pa_tnc_attr_t *ita_attr_command_create(char *command) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -155,8 +148,7 @@ pa_tnc_attr_t *ita_attr_command_create(char *command) }, .get_command = _get_command, }, - .vendor_id = PEN_ITA, - .type = ITA_ATTR_COMMAND, + .type = { PEN_ITA, ITA_ATTR_COMMAND }, .command = strdup(command), .ref = 1, ); @@ -174,7 +166,6 @@ pa_tnc_attr_t *ita_attr_command_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .build = _build, @@ -184,8 +175,7 @@ pa_tnc_attr_t *ita_attr_command_create_from_data(chunk_t data) }, .get_command = _get_command, }, - .vendor_id = PEN_ITA, - .type = ITA_ATTR_COMMAND, + .type = {PEN_ITA, ITA_ATTR_COMMAND }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libimcv/ita/ita_attr_dummy.c b/src/libimcv/ita/ita_attr_dummy.c new file mode 100644 index 000000000..f122256a1 --- /dev/null +++ b/src/libimcv/ita/ita_attr_dummy.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ita_attr.h" +#include "ita_attr_dummy.h" + +#include + +#include + +typedef struct private_ita_attr_dummy_t private_ita_attr_dummy_t; + +/** + * Private data of an ita_attr_dummy_t object. + */ +struct private_ita_attr_dummy_t { + + /** + * Public members of ita_attr_dummy_t + */ + ita_attr_dummy_t public; + + /** + * Vendor-specific attribute type + */ + pen_type_t type; + + /** + * Attribute value + */ + chunk_t value; + + /** + * Noskip flag + */ + bool noskip_flag; + + /** + * Size of the attribute value + */ + int size; + + /** + * Reference count + */ + refcount_t ref; +}; + +METHOD(pa_tnc_attr_t, get_type, pen_type_t, + private_ita_attr_dummy_t *this) +{ + return this->type; +} + +METHOD(pa_tnc_attr_t, get_value, chunk_t, + private_ita_attr_dummy_t *this) +{ + return this->value; +} + +METHOD(pa_tnc_attr_t, get_noskip_flag, bool, + private_ita_attr_dummy_t *this) +{ + return this->noskip_flag; +} + +METHOD(pa_tnc_attr_t, set_noskip_flag,void, + private_ita_attr_dummy_t *this, bool noskip) +{ + this->noskip_flag = noskip; +} + +METHOD(pa_tnc_attr_t, build, void, + private_ita_attr_dummy_t *this) +{ + if (this->value.ptr) + { + return; + } + this->value = chunk_alloc(this->size); + memset(this->value.ptr, 0xdd, this->value.len); +} + +METHOD(pa_tnc_attr_t, process, status_t, + private_ita_attr_dummy_t *this, u_int32_t *offset) +{ + this->size = this->value.len; + + return SUCCESS; +} + +METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*, + private_ita_attr_dummy_t *this) +{ + ref_get(&this->ref); + return &this->public.pa_tnc_attribute; +} + +METHOD(pa_tnc_attr_t, destroy, void, + private_ita_attr_dummy_t *this) +{ + if (ref_put(&this->ref)) + { + free(this->value.ptr); + free(this); + } +} + +METHOD(ita_attr_dummy_t, get_size, int, + private_ita_attr_dummy_t *this) +{ + return this->size; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ita_attr_dummy_create(int size) +{ + private_ita_attr_dummy_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .get_noskip_flag = _get_noskip_flag, + .set_noskip_flag = _set_noskip_flag, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_size = _get_size, + }, + .type = { PEN_ITA, ITA_ATTR_DUMMY }, + .size = size, + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + +/** + * Described in header. + */ +pa_tnc_attr_t *ita_attr_dummy_create_from_data(chunk_t data) +{ + private_ita_attr_dummy_t *this; + + INIT(this, + .public = { + .pa_tnc_attribute = { + .get_type = _get_type, + .get_value = _get_value, + .build = _build, + .process = _process, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .get_size = _get_size, + }, + .type = { PEN_ITA, ITA_ATTR_DUMMY }, + .value = chunk_clone(data), + .ref = 1, + ); + + return &this->public.pa_tnc_attribute; +} + + diff --git a/src/libimcv/ita/ita_attr_dummy.h b/src/libimcv/ita/ita_attr_dummy.h new file mode 100644 index 000000000..afd543b52 --- /dev/null +++ b/src/libimcv/ita/ita_attr_dummy.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ita_attr_dummyt ita_attr_dummy + * @{ @ingroup ita_attr_dummy + */ + +#ifndef ITA_ATTR_DUMMY_H_ +#define ITA_ATTR_DUMMY_H_ + +typedef struct ita_attr_dummy_t ita_attr_dummy_t; + +#include "pa_tnc/pa_tnc_attr.h" + +/** + * Class implementing the ITA Dummy PA-TNC attribute. + * + */ +struct ita_attr_dummy_t { + + /** + * Public PA-TNC attribute interface + */ + pa_tnc_attr_t pa_tnc_attribute; + + /** + * Get the size the ITA Dummy attribute value + * + * @return size of dummy attribute value + */ + int (*get_size)(ita_attr_dummy_t *this); +}; + +/** + * Creates an ita_attr_dummy_t object with a given size + * + * @param size size of dummy attribute value + */ +pa_tnc_attr_t* ita_attr_dummy_create(int size); + +/** + * Creates an ita_attr_dummy_t object from received data + * + * @param command ITA command string + */ +pa_tnc_attr_t* ita_attr_dummy_create_from_data(chunk_t value); + +#endif /** ITA_ATTR_DUMMY_H_ @}*/ diff --git a/src/libimcv/pa_tnc/pa_tnc_attr.h b/src/libimcv/pa_tnc/pa_tnc_attr.h index b6057a70b..9abdba78c 100644 --- a/src/libimcv/pa_tnc/pa_tnc_attr.h +++ b/src/libimcv/pa_tnc/pa_tnc_attr.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -33,18 +33,11 @@ typedef struct pa_tnc_attr_t pa_tnc_attr_t; struct pa_tnc_attr_t { /** - * Get the vendor ID of an PA-TNC attribute + * Get the vendor ID/type of an PA-TNC attribute * - * @return attribute vendor ID + * @return vendor-specific attribute type */ - u_int32_t (*get_vendor_id)(pa_tnc_attr_t *this); - - /** - * Get the type of an PA-TNC attribute - * - * @return attribute type - */ - u_int32_t (*get_type)(pa_tnc_attr_t *this); + pen_type_t (*get_type)(pa_tnc_attr_t *this); /** * Get the value of an PA-TNC attribute diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.c b/src/libimcv/pa_tnc/pa_tnc_msg.c index b5df0a5b5..b1476fc7f 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.c +++ b/src/libimcv/pa_tnc/pa_tnc_msg.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -89,6 +88,16 @@ struct private_pa_tnc_msg_t { */ u_int32_t identifier; + /** + * Current PA-TNC Message size + */ + size_t msg_len; + + /** + * Maximum PA-TNC Message size + */ + size_t max_msg_len; + /** * Encoded message */ @@ -101,67 +110,84 @@ METHOD(pa_tnc_msg_t, get_encoding, chunk_t, return this->encoding; } -METHOD(pa_tnc_msg_t, add_attribute, void, +METHOD(pa_tnc_msg_t, add_attribute, bool, private_pa_tnc_msg_t *this, pa_tnc_attr_t *attr) { + chunk_t attr_value; + size_t attr_len; + + attr->build(attr); + attr_value = attr->get_value(attr); + attr_len = PA_TNC_ATTR_HEADER_SIZE + attr_value.len; + + if (this->max_msg_len && this->msg_len + attr_len > this->max_msg_len) + { + /* attribute just does not fit into this message */ + return FALSE; + } + this->msg_len += attr_len; + this->attributes->insert_last(this->attributes, attr); + return TRUE; } -METHOD(pa_tnc_msg_t, build, void, +METHOD(pa_tnc_msg_t, build, bool, private_pa_tnc_msg_t *this) { bio_writer_t *writer; enumerator_t *enumerator; pa_tnc_attr_t *attr; enum_name_t *pa_attr_names; - pen_t vendor_id; - u_int32_t type; + pen_type_t type; u_int8_t flags; chunk_t value; - rng_t *rng; + nonce_gen_t *ng; - /* create a random message identifier */ - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, sizeof(this->identifier), (u_int8_t*)&this->identifier); - rng->destroy(rng); - DBG2(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier); + /* generate a nonce as a message identifier */ + ng = lib->crypto->create_nonce_gen(lib->crypto); + if (!ng || !ng->get_nonce(ng, 4, (u_int8_t*)&this->identifier)) + { + DBG1(DBG_TNC, "failed to generate random PA-TNC message identifier"); + DESTROY_IF(ng); + return FALSE; + } + ng->destroy(ng); + DBG1(DBG_TNC, "creating PA-TNC message with ID 0x%08x", this->identifier); /* build message header */ - writer = bio_writer_create(PA_TNC_HEADER_SIZE); + writer = bio_writer_create(this->msg_len); writer->write_uint8 (writer, PA_TNC_VERSION); writer->write_uint24(writer, PA_TNC_RESERVED); writer->write_uint32(writer, this->identifier); - /* build and append encoding of PA-TNC attributes */ + /* append encoded value of PA-TNC attributes */ enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attr)) { - attr->build(attr); - vendor_id = attr->get_vendor_id(attr); - type = attr->get_type(attr); + type = attr->get_type(attr); value = attr->get_value(attr); flags = attr->get_noskip_flag(attr) ? PA_TNC_ATTR_FLAG_NOSKIP : PA_TNC_ATTR_FLAG_NONE; pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes, - vendor_id); + type.vendor_id); if (pa_attr_names) { DBG2(DBG_TNC, "creating PA-TNC attribute type '%N/%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - pa_attr_names, type, vendor_id, type); + "0x%06x/0x%08x", pen_names, type.vendor_id, + pa_attr_names, type.type, type.vendor_id, type.type); } else { DBG2(DBG_TNC, "creating PA-TNC attribute type '%N' " - "0x%06x/0x%08x", pen_names, vendor_id, - vendor_id, type); + "0x%06x/0x%08x", pen_names, type.vendor_id, + type.vendor_id, type.type); } DBG3(DBG_TNC, "%B", &value); writer->write_uint8 (writer, flags); - writer->write_uint24(writer, vendor_id); - writer->write_uint32(writer, type); + writer->write_uint24(writer, type.vendor_id); + writer->write_uint32(writer, type.type); writer->write_uint32(writer, PA_TNC_ATTR_HEADER_SIZE + value.len); writer->write_data (writer, value); } @@ -170,6 +196,8 @@ METHOD(pa_tnc_msg_t, build, void, free(this->encoding.ptr); this->encoding = chunk_clone(writer->get_buf(writer)); writer->destroy(writer); + + return TRUE; } METHOD(pa_tnc_msg_t, process, status_t, @@ -179,6 +207,7 @@ METHOD(pa_tnc_msg_t, process, status_t, pa_tnc_attr_t *error; u_int8_t version; u_int32_t reserved, offset, attr_offset; + pen_type_t error_code; /* process message header */ if (this->encoding.len < PA_TNC_HEADER_SIZE) @@ -191,13 +220,14 @@ METHOD(pa_tnc_msg_t, process, status_t, reader->read_uint8 (reader, &version); reader->read_uint24(reader, &reserved); reader->read_uint32(reader, &this->identifier); - DBG2(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier); + DBG1(DBG_TNC, "processing PA-TNC message with ID 0x%08x", this->identifier); if (version != PA_TNC_VERSION) { + pen_type_t error_code = { PEN_IETF, PA_ERROR_VERSION_NOT_SUPPORTED }; + DBG1(DBG_TNC, "PA-TNC version %u not supported", version); - error = ietf_attr_pa_tnc_error_create(PEN_IETF, - PA_ERROR_VERSION_NOT_SUPPORTED, this->encoding); + error = ietf_attr_pa_tnc_error_create(error_code, this->encoding); goto err; } @@ -214,6 +244,7 @@ METHOD(pa_tnc_msg_t, process, status_t, pa_tnc_attr_t *attr; enum_name_t *pa_attr_names; ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; attr_info = reader->peek(reader); attr_info.len = PA_TNC_ATTR_INFO_SIZE; @@ -241,18 +272,18 @@ METHOD(pa_tnc_msg_t, process, status_t, { DBG1(DBG_TNC, "%u bytes too small for PA-TNC attribute length", length); - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, - offset + PA_TNC_ATTR_INFO_SIZE); + error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER); + error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + this->encoding, offset + PA_TNC_ATTR_INFO_SIZE); goto err; } if (!reader->read_data(reader, length - PA_TNC_ATTR_HEADER_SIZE, &value)) { DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute value"); - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, - offset + PA_TNC_ATTR_INFO_SIZE); + error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER); + error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + this->encoding, offset + PA_TNC_ATTR_INFO_SIZE); goto err; } DBG3(DBG_TNC, "%B", &value); @@ -264,8 +295,10 @@ METHOD(pa_tnc_msg_t, process, status_t, if (flags & PA_TNC_ATTR_FLAG_NOSKIP) { DBG1(DBG_TNC, "unsupported PA-TNC attribute with NOSKIP flag"); - error = ietf_attr_pa_tnc_error_create(PEN_IETF, - PA_ERROR_ATTR_TYPE_NOT_SUPPORTED, this->encoding); + error_code = pen_type_create(PEN_IETF, + PA_ERROR_ATTR_TYPE_NOT_SUPPORTED); + error = ietf_attr_pa_tnc_error_create(error_code, + this->encoding); error_attr = (ietf_attr_pa_tnc_error_t*)error; error_attr->set_attr_info(error_attr, attr_info); goto err; @@ -281,18 +314,21 @@ METHOD(pa_tnc_msg_t, process, status_t, if (attr->process(attr, &attr_offset) != SUCCESS) { attr->destroy(attr); - if (vendor_id == PEN_IETF && type == IETF_ATTR_PA_TNC_ERROR) + if (error_code.vendor_id == PEN_IETF && + error_code.type == IETF_ATTR_PA_TNC_ERROR) { /* error while processing a PA-TNC error attribute - abort */ reader->destroy(reader); return FAILED; } - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, + error_code = pen_type_create(PEN_IETF, + PA_ERROR_ATTR_TYPE_NOT_SUPPORTED); + error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + this->encoding, offset + PA_TNC_ATTR_HEADER_SIZE + attr_offset); goto err; } - add_attribute(this, attr); + this->attributes->insert_last(this->attributes, attr); offset += length; } @@ -302,8 +338,9 @@ METHOD(pa_tnc_msg_t, process, status_t, return SUCCESS; } DBG1(DBG_TNC, "insufficient bytes for PA-TNC attribute header"); - error = ietf_attr_pa_tnc_error_create_with_offset(PEN_IETF, - PA_ERROR_INVALID_PARAMETER, this->encoding, offset); + error_code = pen_type_create(PEN_IETF, PA_ERROR_INVALID_PARAMETER); + error = ietf_attr_pa_tnc_error_create_with_offset(error_code, + this->encoding, offset); err: reader->destroy(reader); @@ -316,35 +353,35 @@ METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool, { enumerator_t *enumerator; pa_tnc_attr_t *attr; + pen_type_t type; bool fatal_error = FALSE; enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PA_TNC_ERROR) { ietf_attr_pa_tnc_error_t *error_attr; - pen_t error_vendor_id; - pa_tnc_error_code_t error_code; + pen_type_t error_code; chunk_t msg_info, attr_info; u_int32_t offset; error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_vendor_id = error_attr->get_vendor_id(error_attr); error_code = error_attr->get_error_code(error_attr); msg_info = error_attr->get_msg_info(error_attr); /* skip errors from non-IETF namespaces */ - if (error_vendor_id != PEN_IETF) + if (error_code.vendor_id != PEN_IETF) { continue; } DBG1(DBG_IMC, "received PA-TNC error '%N' concerning message " - "0x%08x/0x%08x", pa_tnc_error_code_names, error_code, + "0x%08x/0x%08x", pa_tnc_error_code_names, error_code.type, untoh32(msg_info.ptr), untoh32(msg_info.ptr + 4)); - switch (error_code) + switch (error_code.type) { case PA_ERROR_INVALID_PARAMETER: offset = error_attr->get_offset(error_attr); @@ -358,8 +395,9 @@ METHOD(pa_tnc_msg_t, process_ietf_std_errors, bool, break; } - /* remove the processed IETF standard error attribute */ + /* remove and delete the processed IETF standard error attribute */ this->attributes->remove_at(this->attributes, enumerator); + attr->destroy(attr); fatal_error = TRUE; } } @@ -394,7 +432,7 @@ METHOD(pa_tnc_msg_t, destroy, void, /** * See header */ -pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) +pa_tnc_msg_t *pa_tnc_msg_create(size_t max_msg_len) { private_pa_tnc_msg_t *this; @@ -409,9 +447,10 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) .create_error_enumerator = _create_error_enumerator, .destroy = _destroy, }, - .encoding = chunk_clone(data), .attributes = linked_list_create(), .errors = linked_list_create(), + .msg_len = PA_TNC_HEADER_SIZE, + .max_msg_len = max_msg_len, ); return &this->public; @@ -420,8 +459,26 @@ pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) /** * See header */ -pa_tnc_msg_t *pa_tnc_msg_create(void) +pa_tnc_msg_t *pa_tnc_msg_create_from_data(chunk_t data) { - return pa_tnc_msg_create_from_data(chunk_empty); + private_pa_tnc_msg_t *this; + + INIT(this, + .public = { + .get_encoding = _get_encoding, + .add_attribute = _add_attribute, + .build = _build, + .process = _process, + .process_ietf_std_errors = _process_ietf_std_errors, + .create_attribute_enumerator = _create_attribute_enumerator, + .create_error_enumerator = _create_error_enumerator, + .destroy = _destroy, + }, + .encoding = chunk_clone(data), + .attributes = linked_list_create(), + .errors = linked_list_create(), + ); + + return &this->public; } diff --git a/src/libimcv/pa_tnc/pa_tnc_msg.h b/src/libimcv/pa_tnc/pa_tnc_msg.h index c3ce829d5..80016fecd 100644 --- a/src/libimcv/pa_tnc/pa_tnc_msg.h +++ b/src/libimcv/pa_tnc/pa_tnc_msg.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -46,13 +46,16 @@ struct pa_tnc_msg_t { * Add a PA-TNC attribute * * @param attr PA-TNC attribute to be addedd + * @return TRUE if attribute fit into message and was added */ - void (*add_attribute)(pa_tnc_msg_t *this, pa_tnc_attr_t* attr); + bool (*add_attribute)(pa_tnc_msg_t *this, pa_tnc_attr_t* attr); /** * Build the PA-TNC message + * + * @return TRUE if PA-TNC message was built successfully */ - void (*build)(pa_tnc_msg_t *this); + bool (*build)(pa_tnc_msg_t *this); /** * Process the PA-TNC message @@ -91,7 +94,7 @@ struct pa_tnc_msg_t { /** * Create an empty PA-TNC message */ -pa_tnc_msg_t* pa_tnc_msg_create(void); +pa_tnc_msg_t* pa_tnc_msg_create(size_t max_msg_len); /** * Create an unprocessed PA-TNC message from received data diff --git a/src/libimcv/plugins/imc_scanner/Makefile.in b/src/libimcv/plugins/imc_scanner/Makefile.in index 497d317d5..d06798170 100644 --- a/src/libimcv/plugins/imc_scanner/Makefile.in +++ b/src/libimcv/plugins/imc_scanner/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -81,7 +82,7 @@ imc_scanner_la_OBJECTS = $(am_imc_scanner_la_OBJECTS) imc_scanner_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(imc_scanner_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -107,6 +108,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -201,11 +203,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -222,11 +227,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -242,6 +248,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -251,7 +258,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner.c b/src/libimcv/plugins/imc_scanner/imc_scanner.c index b24c39c3a..34c9359fe 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -19,8 +20,8 @@ #include #include #include +#include -#include #include #include @@ -37,7 +38,7 @@ static const char imc_name[] = "Scanner"; #define IMC_SUBTYPE PA_SUBTYPE_ITA_SCANNER static imc_agent_t *imc_scanner; - + /** * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3 */ @@ -84,6 +85,15 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_scanner_state_create(connection_id); return imc_scanner->create_state(imc_scanner, state); + case TNC_CONNECTION_STATE_HANDSHAKE: + if (imc_scanner->change_state(imc_scanner, connection_id, new_state, + &state) != TNC_RESULT_SUCCESS) + { + return TNC_RESULT_FATAL; + } + state->set_result(state, imc_id, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_scanner->delete_state(imc_scanner, connection_id); default: @@ -123,7 +133,7 @@ static bool do_netstat(ietf_attr_port_filter_t *attr) enumerator_t *enumerator; bool allowed, found = FALSE; - DBG2(DBG_IMC, "%.*s", strlen(buf)-1, buf); + DBG2(DBG_IMC, "%.*s", (int)(strlen(buf)-1), buf); if (n++ < 2) { @@ -199,7 +209,7 @@ static bool do_netstat(ietf_attr_port_filter_t *attr) } } enumerator->destroy(enumerator); - + /* Skip the duplicate port entry */ if (found) { @@ -221,7 +231,7 @@ end: static TNC_Result send_message(TNC_ConnectionID connection_id) { - pa_tnc_msg_t *msg; + linked_list_t *attr_list; pa_tnc_attr_t *attr; ietf_attr_port_filter_t *attr_port_filter; TNC_Result result; @@ -234,12 +244,11 @@ static TNC_Result send_message(TNC_ConnectionID connection_id) attr->destroy(attr); return TNC_RESULT_FATAL; } - msg = pa_tnc_msg_create(); - msg->add_attribute(msg, attr); - msg->build(msg); + attr_list = linked_list_create(); + attr_list->insert_last(attr_list, attr); result = imc_scanner->send_message(imc_scanner, connection_id, FALSE, 0, - TNC_IMVID_ANY, msg->get_encoding(msg)); - msg->destroy(msg); + TNC_IMVID_ANY, attr_list); + attr_list->destroy(attr_list); return result; } @@ -268,8 +277,12 @@ static TNC_Result receive_message(TNC_IMCID imc_id, TNC_UInt32 dst_imc_id) { pa_tnc_msg_t *pa_tnc_msg; + pa_tnc_attr_t *attr; + pen_type_t attr_type; imc_state_t *state; + enumerator_t *enumerator; TNC_Result result; + TNC_UInt32 target_imc_id; bool fatal_error; if (!imc_scanner) @@ -284,7 +297,7 @@ static TNC_Result receive_message(TNC_IMCID imc_id, return TNC_RESULT_FATAL; } - /* parse received PA-TNC message and automatically handle any errors */ + /* parse received PA-TNC message and automatically handle any errors */ result = imc_scanner->receive_message(imc_scanner, state, msg, msg_vid, msg_subtype, src_imv_id, dst_imc_id, &pa_tnc_msg); @@ -293,17 +306,43 @@ static TNC_Result receive_message(TNC_IMCID imc_id, { return result; } + target_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? imc_id : dst_imc_id; /* preprocess any IETF standard error attributes */ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); + + /* analyze PA-TNC attributes */ + enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); + while (enumerator->enumerate(enumerator, &attr)) + { + attr_type = attr->get_type(attr); + + if (attr_type.vendor_id == PEN_IETF && + attr_type.type == IETF_ATTR_ASSESSMENT_RESULT) + { + ietf_attr_assess_result_t *ietf_attr; + + ietf_attr = (ietf_attr_assess_result_t*)attr; + state->set_result(state, target_imc_id, + ietf_attr->get_result(ietf_attr)); + } + } + enumerator->destroy(enumerator); pa_tnc_msg->destroy(pa_tnc_msg); - /* if no error occurred then always return the same response */ - return fatal_error ? TNC_RESULT_FATAL : send_message(connection_id); + if (fatal_error) + { + return TNC_RESULT_FATAL; + } + + /* if no assessment result is known then repeat the measurement */ + return state->get_result(state, target_imc_id, NULL) ? + TNC_RESULT_SUCCESS : send_message(connection_id); } /** * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3 + */ TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id, TNC_ConnectionID connection_id, diff --git a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c index 563105548..991b24a73 100644 --- a/src/libimcv/plugins/imc_scanner/imc_scanner_state.c +++ b/src/libimcv/plugins/imc_scanner/imc_scanner_state.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,6 +15,8 @@ #include "imc_scanner_state.h" +#include + #include typedef struct private_imc_scanner_state_t private_imc_scanner_state_t; @@ -38,6 +41,11 @@ struct private_imc_scanner_state_t { */ TNC_ConnectionState state; + /** + * Assessment/Evaluation Result + */ + TNC_IMV_Evaluation_Result result; + /** * Does the TNCCS connection support long message types? */ @@ -48,6 +56,10 @@ struct private_imc_scanner_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; }; METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, @@ -75,12 +87,44 @@ METHOD(imc_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imc_state_t, set_max_msg_len, void, + private_imc_scanner_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imc_state_t, get_max_msg_len, u_int32_t, + private_imc_scanner_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imc_state_t, change_state, void, private_imc_scanner_state_t *this, TNC_ConnectionState new_state) { this->state = new_state; } +METHOD(imc_state_t, set_result, void, + private_imc_scanner_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result) +{ + DBG1(DBG_IMC, "set assessment result for IMC %u to '%N'", + id, TNC_IMV_Evaluation_Result_names, result); + this->result = result; +} + +METHOD(imc_state_t, get_result, bool, + private_imc_scanner_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result) +{ + if (result) + { + *result = this->result; + } + return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_scanner_state_t *this) { @@ -101,11 +145,16 @@ imc_state_t *imc_scanner_state_create(TNC_ConnectionID connection_id) .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, + .set_result = _set_result, + .get_result = _get_result, .destroy = _destroy, }, }, .state = TNC_CONNECTION_STATE_CREATE, + .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .connection_id = connection_id, ); diff --git a/src/libimcv/plugins/imc_test/Makefile.in b/src/libimcv/plugins/imc_test/Makefile.in index b4e3f8ae0..8e37e7e9e 100644 --- a/src/libimcv/plugins/imc_test/Makefile.in +++ b/src/libimcv/plugins/imc_test/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -81,7 +82,7 @@ imc_test_la_OBJECTS = $(am_imc_test_la_OBJECTS) imc_test_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(imc_test_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -107,6 +108,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -201,11 +203,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -222,11 +227,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -242,6 +248,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -251,7 +258,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libimcv/plugins/imc_test/imc_test.c b/src/libimcv/plugins/imc_test/imc_test.c index fe005ed4a..ee8e5b206 100644 --- a/src/libimcv/plugins/imc_test/imc_test.c +++ b/src/libimcv/plugins/imc_test/imc_test.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -18,10 +19,11 @@ #include #include #include +#include #include #include +#include -#include #include #include @@ -73,9 +75,12 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, imc_state_t *state; imc_test_state_t *test_state; TNC_Result result; + TNC_UInt32 additional_id; char *command; bool retry; - int additional_ids; + void *pointer; + enumerator_t *enumerator; + int dummy_size, additional_ids; if (!imc_test) { @@ -88,9 +93,12 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: command = lib->settings->get_str(lib->settings, "libimcv.plugins.imc-test.command", "none"); + dummy_size = lib->settings->get_int(lib->settings, + "libimcv.plugins.imc-test.dummy_size", 0); retry = lib->settings->get_bool(lib->settings, "libimcv.plugins.imc-test.retry", FALSE); - state = imc_test_state_create(connection_id, command, retry); + state = imc_test_state_create(connection_id, command, dummy_size, + retry); result = imc_test->create_state(imc_test, state); if (result != TNC_RESULT_SUCCESS) @@ -124,6 +132,26 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, test_state->get_command(test_state)); test_state->set_command(test_state, command); } + + state->set_result(state, imc_id, TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + + /* Exit if there are no additional IMC IDs */ + if (!imc_test->count_additional_ids(imc_test)) + { + return result; + } + + enumerator = imc_test->create_id_enumerator(imc_test); + while (enumerator->enumerate(enumerator, &pointer)) + { + /* interpret pointer as scalar value */ + additional_id = (TNC_UInt32)pointer; + + state->set_result(state, additional_id, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + } + enumerator->destroy(enumerator); + return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: @@ -158,23 +186,30 @@ static TNC_Result send_message(imc_state_t *state, TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id) { imc_test_state_t *test_state; - pa_tnc_msg_t *msg; + linked_list_t *attr_list; pa_tnc_attr_t *attr; bool excl; TNC_ConnectionID connection_id; TNC_Result result; + attr_list = linked_list_create(); connection_id = state->get_connection_id(state); test_state = (imc_test_state_t*)state; + + if (test_state->get_dummy_size(test_state)) + { + attr = ita_attr_dummy_create(test_state->get_dummy_size(test_state)); + attr->set_noskip_flag(attr, TRUE); + attr_list->insert_last(attr_list, attr); + } attr = ita_attr_command_create(test_state->get_command(test_state)); attr->set_noskip_flag(attr, TRUE); - msg = pa_tnc_msg_create(); - msg->add_attribute(msg, attr); - msg->build(msg); + attr_list->insert_last(attr_list, attr); + excl = dst_imv_id != TNC_IMVID_ANY; result = imc_test->send_message(imc_test, connection_id, excl, src_imc_id, - dst_imv_id, msg->get_encoding(msg)); - msg->destroy(msg); + dst_imv_id, attr_list); + attr_list->destroy(attr_list); return result; } @@ -245,9 +280,11 @@ static TNC_Result receive_message(TNC_IMCID imc_id, { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + pen_type_t attr_type; imc_state_t *state; enumerator_t *enumerator; TNC_Result result; + TNC_UInt32 target_imc_id; bool fatal_error = FALSE; if (!imc_test) @@ -271,6 +308,7 @@ static TNC_Result receive_message(TNC_IMCID imc_id, { return result; } + target_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? imc_id : dst_imc_id; /* preprocess any IETF standard error attributes */ fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg); @@ -279,22 +317,47 @@ static TNC_Result receive_message(TNC_IMCID imc_id, enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_ITA && - attr->get_type(attr) == ITA_ATTR_COMMAND) + attr_type = attr->get_type(attr); + + if (attr_type.vendor_id == PEN_IETF) { - ita_attr_command_t *ita_attr; - char *command; - - ita_attr = (ita_attr_command_t*)attr; - command = ita_attr->get_command(ita_attr); + ietf_attr_assess_result_t *ietf_attr; + + ietf_attr = (ietf_attr_assess_result_t*)attr; + state->set_result(state, target_imc_id, + ietf_attr->get_result(ietf_attr)); + } + else if (attr_type.vendor_id == PEN_ITA) + { + if (attr_type.type == ITA_ATTR_COMMAND) + { + ita_attr_command_t *ita_attr; + + ita_attr = (ita_attr_command_t*)attr; + DBG1(DBG_IMC, "received command '%s'", + ita_attr->get_command(ita_attr)); + } + else if (attr_type.type == ITA_ATTR_DUMMY) + { + ita_attr_dummy_t *ita_attr; + + ita_attr = (ita_attr_dummy_t*)attr; + DBG1(DBG_IMC, "received dummy attribute value (%d bytes)", + ita_attr->get_size(ita_attr)); + } } } enumerator->destroy(enumerator); pa_tnc_msg->destroy(pa_tnc_msg); - /* if no error occurred then always return the same response */ - return fatal_error ? TNC_RESULT_FATAL : - send_message(state, dst_imc_id, src_imv_id); + if (fatal_error) + { + return TNC_RESULT_FATAL; + } + + /* if no assessment result is known then repeat the measurement */ + return state->get_result(state, target_imc_id, NULL) ? + TNC_RESULT_SUCCESS : send_message(state, dst_imc_id, src_imv_id); } /** diff --git a/src/libimcv/plugins/imc_test/imc_test_state.c b/src/libimcv/plugins/imc_test/imc_test_state.c index 2adfd7d64..e70eb1492 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.c +++ b/src/libimcv/plugins/imc_test/imc_test_state.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,10 +15,13 @@ #include "imc_test_state.h" +#include + #include #include typedef struct private_imc_test_state_t private_imc_test_state_t; +typedef struct entry_t entry_t; /** * Private data of an imc_test_state_t object. @@ -39,6 +43,11 @@ struct private_imc_test_state_t { */ TNC_ConnectionState state; + /** + * Assessment/Evaluation Results for all IMC IDs + */ + linked_list_t *results; + /** * Does the TNCCS connection support long message types? */ @@ -49,11 +58,21 @@ struct private_imc_test_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + /** * Command to transmit to IMV */ char *command; + /** + * Size of the dummy attribute value to transmit to IMV + */ + int dummy_size; + /** * Is it the first handshake? */ @@ -66,6 +85,14 @@ struct private_imc_test_state_t { }; +/** + * Stores the Assessment/Evaluation Result for a given IMC ID + */ +struct entry_t { + TNC_IMCID id; + TNC_IMV_Evaluation_Result result; +}; + METHOD(imc_state_t, get_connection_id, TNC_ConnectionID, private_imc_test_state_t *this) { @@ -91,15 +118,86 @@ METHOD(imc_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imc_state_t, set_max_msg_len, void, + private_imc_test_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imc_state_t, get_max_msg_len, u_int32_t, + private_imc_test_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imc_state_t, change_state, void, private_imc_test_state_t *this, TNC_ConnectionState new_state) { this->state = new_state; } +METHOD(imc_state_t, set_result, void, + private_imc_test_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result) +{ + enumerator_t *enumerator; + entry_t *entry; + bool found = FALSE; + + DBG1(DBG_IMC, "set assessment result for IMC %u to '%N'", + id, TNC_IMV_Evaluation_Result_names, result); + + enumerator = this->results->create_enumerator(this->results); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->id == id) + { + entry->result = result; + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + entry = malloc_thing(entry_t); + entry->id = id; + entry->result = result; + this->results->insert_last(this->results, entry); + } +} + +METHOD(imc_state_t, get_result, bool, + private_imc_test_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result) +{ + enumerator_t *enumerator; + entry_t *entry; + TNC_IMV_Evaluation_Result eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW; + + enumerator = this->results->create_enumerator(this->results); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->id == id) + { + eval = entry->result; + break; + } + } + enumerator->destroy(enumerator); + + if (result) + { + *result = eval; + } + return eval != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} + METHOD(imc_state_t, destroy, void, private_imc_test_state_t *this) { + this->results->destroy_function(this->results, free); free(this->command); free(this); } @@ -120,6 +218,13 @@ METHOD(imc_test_state_t, set_command, void, free(old_command); } +METHOD(imc_test_state_t, get_dummy_size, int, + private_imc_test_state_t *this) +{ + return this->dummy_size; +} + + METHOD(imc_test_state_t, is_first_handshake, bool, private_imc_test_state_t *this) { @@ -146,7 +251,7 @@ METHOD(imc_test_state_t, do_handshake_retry, bool, * Described in header. */ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, - char *command, bool retry) + char *command, int dummy_size, bool retry) { private_imc_test_state_t *this; @@ -157,17 +262,24 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, + .set_result = _set_result, + .get_result = _get_result, .destroy = _destroy, }, .get_command = _get_command, .set_command = _set_command, + .get_dummy_size = _get_dummy_size, .is_first_handshake = _is_first_handshake, .do_handshake_retry = _do_handshake_retry, }, .state = TNC_CONNECTION_STATE_CREATE, + .results = linked_list_create(), .connection_id = connection_id, .command = strdup(command), + .dummy_size = dummy_size, .first_handshake = TRUE, .handshake_retry = retry, ); @@ -175,4 +287,3 @@ imc_state_t *imc_test_state_create(TNC_ConnectionID connection_id, return &this->public.interface; } - diff --git a/src/libimcv/plugins/imc_test/imc_test_state.h b/src/libimcv/plugins/imc_test/imc_test_state.h index d9160df94..402fd14b3 100644 --- a/src/libimcv/plugins/imc_test/imc_test_state.h +++ b/src/libimcv/plugins/imc_test/imc_test_state.h @@ -51,6 +51,13 @@ struct imc_test_state_t { */ void (*set_command)(imc_test_state_t *this, char *command); + /** + * get the value size of a dummy attribute to send to IMV + * + * @return size of the dummy attribute value to send to IMV + */ + int (*get_dummy_size)(imc_test_state_t *this); + /** * Test and reset the first handshake flag * @@ -70,11 +77,12 @@ struct imc_test_state_t { /** * Create an imc_test_state_t instance * - * @param id connection ID - * @param command command to send to IMV - * @param retry TRUE if a handshake retry should be done + * @param id connection ID + * @param command command to send to IMV + * @param dummy_size size of the dummy attribute to send (only if > 0) + * @param retry TRUE if a handshake retry should be done */ imc_state_t* imc_test_state_create(TNC_ConnectionID id, char* command, - bool retry); + int dummy_size, bool retry); #endif /** IMC_TEST_STATE_H_ @}*/ diff --git a/src/libimcv/plugins/imv_scanner/Makefile.in b/src/libimcv/plugins/imv_scanner/Makefile.in index 63602c707..126a42c93 100644 --- a/src/libimcv/plugins/imv_scanner/Makefile.in +++ b/src/libimcv/plugins/imv_scanner/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -81,7 +82,7 @@ imv_scanner_la_OBJECTS = $(am_imv_scanner_la_OBJECTS) imv_scanner_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(imv_scanner_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -107,6 +108,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -201,11 +203,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -222,11 +227,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -242,6 +248,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -251,7 +258,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner.c b/src/libimcv/plugins/imv_scanner/imv_scanner.c index dba3fd632..1352397c6 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -186,6 +187,7 @@ static TNC_Result receive_message(TNC_IMVID imv_id, { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + pen_type_t type; imv_state_t *state; enumerator_t *enumerator; TNC_Result result; @@ -220,8 +222,9 @@ static TNC_Result receive_message(TNC_IMVID imv_id, enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PORT_FILTER) + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF && type.type == IETF_ATTR_PORT_FILTER) { ietf_attr_port_filter_t *attr_port_filter; enumerator_t *enumerator; @@ -305,10 +308,9 @@ static TNC_Result receive_message(TNC_IMVID imv_id, state->set_recommendation(state, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); - return imv_scanner->provide_recommendation(imv_scanner, connection_id); } - - return imv_scanner->provide_recommendation(imv_scanner, connection_id); + return imv_scanner->provide_recommendation(imv_scanner, connection_id, + src_imc_id); } /** @@ -359,7 +361,8 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); return TNC_RESULT_NOT_INITIALIZED; } - return imv_scanner->provide_recommendation(imv_scanner, connection_id); + return imv_scanner->provide_recommendation(imv_scanner, connection_id, + TNC_IMCID_ANY); } /** diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c index 422cb980d..fecc84e70 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -49,6 +50,11 @@ struct private_imv_scanner_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + /** * IMV action recommendation */ @@ -115,6 +121,18 @@ METHOD(imv_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imv_state_t, set_max_msg_len, void, + private_imv_scanner_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imv_state_t, get_max_msg_len, u_int32_t, + private_imv_scanner_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imv_state_t, change_state, void, private_imv_scanner_state_t *this, TNC_ConnectionState new_state) { @@ -223,6 +241,8 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libimcv/plugins/imv_test/Makefile.in b/src/libimcv/plugins/imv_test/Makefile.in index e51ad9afd..e395f8187 100644 --- a/src/libimcv/plugins/imv_test/Makefile.in +++ b/src/libimcv/plugins/imv_test/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -81,7 +82,7 @@ imv_test_la_OBJECTS = $(am_imv_test_la_OBJECTS) imv_test_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(imv_test_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -107,6 +108,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -201,11 +203,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -222,11 +227,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -242,6 +248,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -251,7 +258,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libimcv/plugins/imv_test/imv_test.c b/src/libimcv/plugins/imv_test/imv_test.c index 0afd81aec..5ea82e97c 100644 --- a/src/libimcv/plugins/imv_test/imv_test.c +++ b/src/libimcv/plugins/imv_test/imv_test.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -101,12 +103,14 @@ static TNC_Result receive_message(TNC_IMVID imv_id, { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + pen_type_t attr_type; + linked_list_t *attr_list; imv_state_t *state; imv_test_state_t *test_state; enumerator_t *enumerator; TNC_Result result; int rounds; - bool fatal_error, retry = FALSE; + bool fatal_error, received_command = FALSE, retry = FALSE; if (!imv_test) { @@ -143,12 +147,18 @@ static TNC_Result receive_message(TNC_IMVID imv_id, enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_ITA && - attr->get_type(attr) == ITA_ATTR_COMMAND) + attr_type = attr->get_type(attr); + + if (attr_type.vendor_id != PEN_ITA) + { + continue; + } + if (attr_type.type == ITA_ATTR_COMMAND) { ita_attr_command_t *ita_attr; char *command; + received_command = TRUE; ita_attr = (ita_attr_command_t*)attr; command = ita_attr->get_command(ita_attr); @@ -181,7 +191,15 @@ static TNC_Result receive_message(TNC_IMVID imv_id, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); } - } + } + else if (attr_type.type == ITA_ATTR_DUMMY) + { + ita_attr_dummy_t *ita_attr; + + ita_attr = (ita_attr_dummy_t*)attr; + DBG1(DBG_IMV, "received dummy attribute value (%d bytes)", + ita_attr->get_size(ita_attr)); + } } enumerator->destroy(enumerator); pa_tnc_msg->destroy(pa_tnc_msg); @@ -191,7 +209,8 @@ static TNC_Result receive_message(TNC_IMVID imv_id, state->set_recommendation(state, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); - return imv_test->provide_recommendation(imv_test, connection_id); + return imv_test->provide_recommendation(imv_test, connection_id, + src_imc_id); } /* request a handshake retry ? */ @@ -205,18 +224,18 @@ static TNC_Result receive_message(TNC_IMVID imv_id, /* repeat the measurement ? */ if (test_state->another_round(test_state, src_imc_id)) { + attr_list = linked_list_create(); attr = ita_attr_command_create("repeat"); - pa_tnc_msg = pa_tnc_msg_create(); - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - pa_tnc_msg->build(pa_tnc_msg); + attr_list->insert_last(attr_list, attr); result = imv_test->send_message(imv_test, connection_id, TRUE, imv_id, - src_imc_id, pa_tnc_msg->get_encoding(pa_tnc_msg)); - pa_tnc_msg->destroy(pa_tnc_msg); + src_imc_id, attr_list); + attr_list->destroy(attr_list); return result; } - return imv_test->provide_recommendation(imv_test, connection_id); + return received_command ? imv_test->provide_recommendation(imv_test, + connection_id, src_imc_id) : TNC_RESULT_SUCCESS; } /** @@ -267,7 +286,8 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name); return TNC_RESULT_NOT_INITIALIZED; } - return imv_test->provide_recommendation(imv_test, connection_id); + return imv_test->provide_recommendation(imv_test, connection_id, + TNC_IMCID_ANY); } /** diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c index 530090af7..67f22c062 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.c +++ b/src/libimcv/plugins/imv_test/imv_test_state.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil + * Copyright (C) 2011-2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -50,6 +51,11 @@ struct private_imv_test_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + /** * IMV action recommendation */ @@ -122,6 +128,18 @@ METHOD(imv_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imv_state_t, set_max_msg_len, void, + private_imv_test_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imv_state_t, get_max_msg_len, u_int32_t, + private_imv_test_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imv_state_t, change_state, void, private_imv_test_state_t *this, TNC_ConnectionState new_state) { @@ -274,6 +292,8 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libipsec/Android.mk b/src/libipsec/Android.mk new file mode 100644 index 000000000..81f4632ef --- /dev/null +++ b/src/libipsec/Android.mk @@ -0,0 +1,38 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# copy-n-paste from Makefile.am +LOCAL_SRC_FILES := \ +ipsec.c ipsec.h \ +esp_context.c esp_context.h \ +esp_packet.c esp_packet.h \ +ip_packet.c ip_packet.h \ +ipsec_event_listener.h \ +ipsec_event_relay.c ipsec_event_relay.h \ +ipsec_policy.c ipsec_policy.h \ +ipsec_policy_mgr.c ipsec_policy_mgr.h \ +ipsec_processor.c ipsec_processor.h \ +ipsec_sa.c ipsec_sa.h \ +ipsec_sa_mgr.c ipsec_sa_mgr.h + +# build libipsec --------------------------------------------------------------- + +LOCAL_C_INCLUDES += \ + $(libvstr_PATH) \ + $(strongswan_PATH)/src/include \ + $(strongswan_PATH)/src/libstrongswan + +LOCAL_CFLAGS := $(strongswan_CFLAGS) + +LOCAL_MODULE := libipsec + +LOCAL_MODULE_TAGS := optional + +LOCAL_ARM_MODE := arm + +LOCAL_PRELINK_MODULE := false + +LOCAL_SHARED_LIBRARIES += libstrongswan + +include $(BUILD_SHARED_LIBRARY) + diff --git a/src/libipsec/Makefile.am b/src/libipsec/Makefile.am new file mode 100644 index 000000000..35b8d7916 --- /dev/null +++ b/src/libipsec/Makefile.am @@ -0,0 +1,31 @@ +ipseclib_LTLIBRARIES = libipsec.la + +libipsec_la_SOURCES = \ +ipsec.c ipsec.h \ +esp_context.c esp_context.h \ +esp_packet.c esp_packet.h \ +ip_packet.c ip_packet.h \ +ipsec_event_listener.h \ +ipsec_event_relay.c ipsec_event_relay.h \ +ipsec_policy.c ipsec_policy.h \ +ipsec_policy_mgr.c ipsec_policy_mgr.h \ +ipsec_processor.c ipsec_processor.h \ +ipsec_sa.c ipsec_sa.h \ +ipsec_sa_mgr.c ipsec_sa_mgr.h + +libipsec_la_LIBADD = + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan + +EXTRA_DIST = Android.mk + +# build optional plugins +######################## + +if MONOLITHIC +SUBDIRS = +else +SUBDIRS = . +endif + diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in new file mode 100644 index 000000000..6d984d8ab --- /dev/null +++ b/src/libipsec/Makefile.in @@ -0,0 +1,780 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libipsec +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(ipseclibdir)" +LTLIBRARIES = $(ipseclib_LTLIBRARIES) +libipsec_la_DEPENDENCIES = +am_libipsec_la_OBJECTS = ipsec.lo esp_context.lo esp_packet.lo \ + ip_packet.lo ipsec_event_relay.lo ipsec_policy.lo \ + ipsec_policy_mgr.lo ipsec_processor.lo ipsec_sa.lo \ + ipsec_sa_mgr.lo +libipsec_la_OBJECTS = $(am_libipsec_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libipsec_la_SOURCES) +DIST_SOURCES = $(libipsec_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = . +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +ipseclib_LTLIBRARIES = libipsec.la +libipsec_la_SOURCES = \ +ipsec.c ipsec.h \ +esp_context.c esp_context.h \ +esp_packet.c esp_packet.h \ +ip_packet.c ip_packet.h \ +ipsec_event_listener.h \ +ipsec_event_relay.c ipsec_event_relay.h \ +ipsec_policy.c ipsec_policy.h \ +ipsec_policy_mgr.c ipsec_policy_mgr.h \ +ipsec_processor.c ipsec_processor.h \ +ipsec_sa.c ipsec_sa.h \ +ipsec_sa_mgr.c ipsec_sa_mgr.h + +libipsec_la_LIBADD = +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan + +EXTRA_DIST = Android.mk +@MONOLITHIC_FALSE@SUBDIRS = . + +# build optional plugins +######################## +@MONOLITHIC_TRUE@SUBDIRS = +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libipsec/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libipsec/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-ipseclibLTLIBRARIES: $(ipseclib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(ipseclibdir)" || $(MKDIR_P) "$(DESTDIR)$(ipseclibdir)" + @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(ipseclibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(ipseclibdir)"; \ + } + +uninstall-ipseclibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(ipseclib_LTLIBRARIES)'; test -n "$(ipseclibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(ipseclibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(ipseclibdir)/$$f"; \ + done + +clean-ipseclibLTLIBRARIES: + -test -z "$(ipseclib_LTLIBRARIES)" || rm -f $(ipseclib_LTLIBRARIES) + @list='$(ipseclib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libipsec.la: $(libipsec_la_OBJECTS) $(libipsec_la_DEPENDENCIES) + $(LINK) -rpath $(ipseclibdir) $(libipsec_la_OBJECTS) $(libipsec_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esp_context.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/esp_packet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_packet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_event_relay.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_policy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_policy_mgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_processor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_sa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_sa_mgr.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(ipseclibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-ipseclibLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-ipseclibLTLIBRARIES + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-ipseclibLTLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic \ + clean-ipseclibLTLIBRARIES clean-libtool ctags ctags-recursive \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-ipseclibLTLIBRARIES install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-ipseclibLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libipsec/esp_context.c b/src/libipsec/esp_context.c new file mode 100644 index 000000000..dc3ad3f8b --- /dev/null +++ b/src/libipsec/esp_context.c @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include + +#include "esp_context.h" + +#include +#include +#include +#include + +/** + * Should be a multiple of 8 + */ +#define ESP_DEFAULT_WINDOW_SIZE 128 + +typedef struct private_esp_context_t private_esp_context_t; + +/** + * Private additions to esp_context_t. + */ +struct private_esp_context_t { + + /** + * Public members + */ + esp_context_t public; + + /** + * Crypter used to encrypt/decrypt ESP packets + */ + crypter_t *crypter; + + /** + * Signer to authenticate ESP packets + */ + signer_t *signer; + + /** + * The highest sequence number that was successfully verified + * and authenticated, or assigned in an outbound context + */ + u_int32_t last_seqno; + + /** + * The bit in the window of the highest authenticated sequence number + */ + u_int seqno_index; + + /** + * The size of the anti-replay window (in bits) + */ + u_int window_size; + + /** + * The anti-replay window buffer + */ + chunk_t window; + + /** + * TRUE in case of an inbound ESP context + */ + bool inbound; +}; + +/** + * Set or unset a bit in the window. + */ +static inline void set_window_bit(private_esp_context_t *this, + u_int index, bool set) +{ + u_int i = index / CHAR_BIT; + + if (set) + { + this->window.ptr[i] |= 1 << (index % CHAR_BIT); + } + else + { + this->window.ptr[i] &= ~(1 << (index % CHAR_BIT)); + } +} + +/** + * Get a bit from the window. + */ +static inline bool get_window_bit(private_esp_context_t *this, u_int index) +{ + u_int i = index / CHAR_BIT; + + return this->window.ptr[i] & (1 << index % CHAR_BIT); +} + +/** + * Returns TRUE if the supplied seqno is not already marked in the window + */ +static bool check_window(private_esp_context_t *this, u_int32_t seqno) +{ + u_int offset; + + offset = this->last_seqno - seqno; + offset = (this->seqno_index - offset) % this->window_size; + return !get_window_bit(this, offset); +} + +METHOD(esp_context_t, verify_seqno, bool, + private_esp_context_t *this, u_int32_t seqno) +{ + if (!this->inbound) + { + return FALSE; + } + + if (seqno > this->last_seqno) + { /* |----------------------------------------| + * <---------^ ^ or <---------^ ^ + * WIN H S WIN H S + */ + return TRUE; + } + else if (seqno > 0 && this->window_size > this->last_seqno - seqno) + { /* |----------------------------------------| + * <---------^ or <---------^ + * WIN ^ H WIN ^ H + * S S + */ + return check_window(this, seqno); + } + else + { /* |----------------------------------------| + * ^ <---------^ + * S WIN H + */ + return FALSE; + } +} + +METHOD(esp_context_t, set_authenticated_seqno, void, + private_esp_context_t *this, u_int32_t seqno) +{ + u_int i, shift; + + if (!this->inbound) + { + return; + } + + if (seqno > this->last_seqno) + { /* shift the window to the new highest authenticated seqno */ + shift = seqno - this->last_seqno; + shift = shift < this->window_size ? shift : this->window_size; + for (i = 0; i < shift; ++i) + { + this->seqno_index = (this->seqno_index + 1) % this->window_size; + set_window_bit(this, this->seqno_index, FALSE); + } + set_window_bit(this, this->seqno_index, TRUE); + this->last_seqno = seqno; + } + else + { /* seqno is inside the window, set the corresponding window bit */ + i = this->last_seqno - seqno; + set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE); + } +} + +METHOD(esp_context_t, get_seqno, u_int32_t, + private_esp_context_t *this) +{ + return this->last_seqno; +} + +METHOD(esp_context_t, next_seqno, bool, + private_esp_context_t *this, u_int32_t *seqno) +{ + if (this->inbound || this->last_seqno == UINT32_MAX) + { /* inbound or segno would cycle */ + return FALSE; + } + *seqno = ++this->last_seqno; + return TRUE; +} + +METHOD(esp_context_t, get_signer, signer_t *, + private_esp_context_t *this) +{ + return this->signer; +} + +METHOD(esp_context_t, get_crypter, crypter_t *, + private_esp_context_t *this) +{ + return this->crypter; +} + +METHOD(esp_context_t, destroy, void, + private_esp_context_t *this) +{ + chunk_free(&this->window); + DESTROY_IF(this->crypter); + DESTROY_IF(this->signer); + free(this); +} + +/** + * Described in header. + */ +esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key, + int int_alg, chunk_t int_key, bool inbound) +{ + private_esp_context_t *this; + + INIT(this, + .public = { + .get_crypter = _get_crypter, + .get_signer = _get_signer, + .get_seqno = _get_seqno, + .next_seqno = _next_seqno, + .verify_seqno = _verify_seqno, + .set_authenticated_seqno = _set_authenticated_seqno, + .destroy = _destroy, + }, + .inbound = inbound, + .window_size = ESP_DEFAULT_WINDOW_SIZE, + ); + + switch(enc_alg) + { + case ENCR_AES_CBC: + this->crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, + enc_key.len); + break; + default: + break; + } + if (!this->crypter) + { + DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption " + "algorithm"); + destroy(this); + return NULL; + } + if (!this->crypter->set_key(this->crypter, enc_key)) + { + DBG1(DBG_ESP, "failed to create ESP context: setting encryption key " + "failed"); + destroy(this); + return NULL; + } + + switch(int_alg) + { + case AUTH_HMAC_SHA1_96: + case AUTH_HMAC_SHA2_256_128: + case AUTH_HMAC_SHA2_384_192: + case AUTH_HMAC_SHA2_512_256: + this->signer = lib->crypto->create_signer(lib->crypto, int_alg); + break; + default: + break; + } + if (!this->signer) + { + DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity " + "algorithm"); + destroy(this); + return NULL; + } + if (!this->signer->set_key(this->signer, int_key)) + { + DBG1(DBG_ESP, "failed to create ESP context: setting signature key " + "failed"); + destroy(this); + return NULL; + } + + if (inbound) + { + this->window = chunk_alloc(this->window_size / CHAR_BIT + 1); + memset(this->window.ptr, 0, this->window.len); + } + return &this->public; +} + + diff --git a/src/libipsec/esp_context.h b/src/libipsec/esp_context.h new file mode 100644 index 000000000..db247dced --- /dev/null +++ b/src/libipsec/esp_context.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup esp_context esp_context + * @{ @ingroup libipsec + */ + +#ifndef ESP_CONTEXT_H_ +#define ESP_CONTEXT_H_ + +#include +#include +#include + +typedef struct esp_context_t esp_context_t; + +/** + * ESP context, handles sequence numbers and maintains cryptographic primitives + */ +struct esp_context_t { + + /** + * Get the crypter. + * + * @return crypter + */ + crypter_t *(*get_crypter)(esp_context_t *this); + + /** + * Get the signer. + * + * @return signer + */ + signer_t *(*get_signer)(esp_context_t *this); + + /** + * Get the current outbound ESP sequence number or the highest authenticated + * inbound sequence number. + * + * @return current sequence number, in host byte order + */ + u_int32_t (*get_seqno)(esp_context_t *this); + + /** + * Allocate the next outbound ESP sequence number. + * + * @param seqno the sequence number, in host byte order + * @return FALSE if the sequence number cycled or inbound context + */ + bool (*next_seqno)(esp_context_t *this, u_int32_t *seqno); + + /** + * Verify an ESP sequence number. Checks whether a packet with this + * sequence number was already received, using the anti-replay window. + * This operation does not modify the internal state. After the sequence + * number is successfully verified and the ESP packet is authenticated, + * set_authenticated_seqno() should be called. + * + * @param seqno the sequence number to verify, in host byte order + * @return TRUE when sequence number is valid + */ + bool (*verify_seqno)(esp_context_t *this, u_int32_t seqno); + + /** + * Adds a sequence number that was successfully verified and + * authenticated. A user MUST call verify_seqno() immediately before + * calling this method. + * + * @param seqno verified and authenticated seq number in host byte order + */ + void (*set_authenticated_seqno)(esp_context_t *this, + u_int32_t seqno); + + /** + * Destroy an esp_context_t + */ + void (*destroy)(esp_context_t *this); + +}; + +/** + * Create an esp_context_t instance + * + * @param enc_alg encryption algorithm + * @param enc_key encryption key + * @param int_alg integrity protection algorithm + * @param int_key integrity protection key + * @param inbound TRUE to create an inbound ESP context + * @return ESP context instance, or NULL if creation fails + */ +esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key, int int_alg, + chunk_t int_key, bool inbound); + +#endif /** ESP_CONTEXT_H_ @}*/ + diff --git a/src/libipsec/esp_packet.c b/src/libipsec/esp_packet.c new file mode 100644 index 000000000..bfcab95eb --- /dev/null +++ b/src/libipsec/esp_packet.c @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + + +#include "esp_packet.h" + +#include +#include +#include +#include +#include +#include + +#include + +typedef struct private_esp_packet_t private_esp_packet_t; + +/** + * Private additions to esp_packet_t. + */ +struct private_esp_packet_t { + + /** + * Public members + */ + esp_packet_t public; + + /** + * Raw ESP packet + */ + packet_t *packet; + + /** + * Payload of this packet + */ + ip_packet_t *payload; + + /** + * Next Header info (e.g. IPPROTO_IPIP) + */ + u_int8_t next_header; + +}; + +/** + * Forward declaration for clone() + */ +static private_esp_packet_t *esp_packet_create_internal(packet_t *packet); + +METHOD(packet_t, set_source, void, + private_esp_packet_t *this, host_t *src) +{ + return this->packet->set_source(this->packet, src); +} + +METHOD2(esp_packet_t, packet_t, get_source, host_t*, + private_esp_packet_t *this) +{ + return this->packet->get_source(this->packet); +} + +METHOD(packet_t, set_destination, void, + private_esp_packet_t *this, host_t *dst) +{ + return this->packet->set_destination(this->packet, dst); +} + +METHOD2(esp_packet_t, packet_t, get_destination, host_t*, + private_esp_packet_t *this) +{ + return this->packet->get_destination(this->packet); +} + +METHOD(packet_t, get_data, chunk_t, + private_esp_packet_t *this) +{ + return this->packet->get_data(this->packet); +} + +METHOD(packet_t, set_data, void, + private_esp_packet_t *this, chunk_t data) +{ + return this->packet->set_data(this->packet, data); +} + +METHOD(packet_t, skip_bytes, void, + private_esp_packet_t *this, size_t bytes) +{ + return this->packet->skip_bytes(this->packet, bytes); +} + +METHOD(packet_t, clone, packet_t*, + private_esp_packet_t *this) +{ + private_esp_packet_t *pkt; + + pkt = esp_packet_create_internal(this->packet->clone(this->packet)); + pkt->payload = this->payload ? this->payload->clone(this->payload) : NULL; + pkt->next_header = this->next_header; + return &pkt->public.packet; +} + +METHOD(esp_packet_t, parse_header, bool, + private_esp_packet_t *this, u_int32_t *spi) +{ + bio_reader_t *reader; + u_int32_t seq; + + reader = bio_reader_create(this->packet->get_data(this->packet)); + if (!reader->read_uint32(reader, spi) || + !reader->read_uint32(reader, &seq)) + { + DBG1(DBG_ESP, "failed to parse ESP header: invalid length"); + reader->destroy(reader); + return FALSE; + } + reader->destroy(reader); + + DBG2(DBG_ESP, "parsed ESP header with SPI %.8x [seq %u]", *spi, seq); + *spi = htonl(*spi); + return TRUE; +} + +/** + * Check padding as specified in RFC 4303 + */ +static bool check_padding(chunk_t padding) +{ + size_t i; + + for (i = 0; i < padding.len; ++i) + { + if (padding.ptr[i] != (u_int8_t)(i + 1)) + { + return FALSE; + } + } + return TRUE; +} + +/** + * Remove the padding from the payload and set the next header info + */ +static bool remove_padding(private_esp_packet_t *this, chunk_t plaintext) +{ + u_int8_t next_header, pad_length; + chunk_t padding, payload; + bio_reader_t *reader; + + reader = bio_reader_create(plaintext); + if (!reader->read_uint8_end(reader, &next_header) || + !reader->read_uint8_end(reader, &pad_length)) + { + DBG1(DBG_ESP, "parsing ESP payload failed: invalid length"); + goto failed; + } + if (!reader->read_data_end(reader, pad_length, &padding) || + !check_padding(padding)) + { + DBG1(DBG_ESP, "parsing ESP payload failed: invalid padding"); + goto failed; + } + this->payload = ip_packet_create(reader->peek(reader)); + reader->destroy(reader); + if (!this->payload) + { + DBG1(DBG_ESP, "parsing ESP payload failed: unsupported payload"); + return FALSE; + } + this->next_header = next_header; + payload = this->payload->get_encoding(this->payload); + + DBG3(DBG_ESP, "ESP payload:\n payload %B\n padding %B\n " + "padding length = %hhu, next header = %hhu", &payload, &padding, + pad_length, this->next_header); + return TRUE; + +failed: + reader->destroy(reader); + chunk_free(&plaintext); + return FALSE; +} + +METHOD(esp_packet_t, decrypt, status_t, + private_esp_packet_t *this, esp_context_t *esp_context) +{ + bio_reader_t *reader; + u_int32_t spi, seq; + chunk_t data, iv, icv, ciphertext, plaintext; + crypter_t *crypter; + signer_t *signer; + + DESTROY_IF(this->payload); + this->payload = NULL; + + data = this->packet->get_data(this->packet); + crypter = esp_context->get_crypter(esp_context); + signer = esp_context->get_signer(esp_context); + + reader = bio_reader_create(data); + if (!reader->read_uint32(reader, &spi) || + !reader->read_uint32(reader, &seq) || + !reader->read_data(reader, crypter->get_iv_size(crypter), &iv) || + !reader->read_data_end(reader, signer->get_block_size(signer), &icv) || + reader->remaining(reader) % crypter->get_block_size(crypter)) + { + DBG1(DBG_ESP, "ESP decryption failed: invalid length"); + return PARSE_ERROR; + } + ciphertext = reader->peek(reader); + reader->destroy(reader); + + if (!esp_context->verify_seqno(esp_context, seq)) + { + DBG1(DBG_ESP, "ESP sequence number verification failed:\n " + "src %H, dst %H, SPI %.8x [seq %u]", + get_source(this), get_destination(this), spi, seq); + return VERIFY_ERROR; + } + DBG3(DBG_ESP, "ESP decryption:\n SPI %.8x [seq %u]\n IV %B\n " + "encrypted %B\n ICV %B", spi, seq, &iv, &ciphertext, &icv); + + if (!signer->get_signature(signer, chunk_create(data.ptr, 8), NULL) || + !signer->get_signature(signer, iv, NULL) || + !signer->verify_signature(signer, ciphertext, icv)) + { + DBG1(DBG_ESP, "ICV verification failed!"); + return FAILED; + } + esp_context->set_authenticated_seqno(esp_context, seq); + + if (!crypter->decrypt(crypter, ciphertext, iv, &plaintext)) + { + DBG1(DBG_ESP, "ESP decryption failed"); + return FAILED; + } + + if (!remove_padding(this, plaintext)) + { + return PARSE_ERROR; + } + return SUCCESS; +} + +/** + * Generate the padding as specified in RFC4303 + */ +static void generate_padding(chunk_t padding) +{ + size_t i; + + for (i = 0; i < padding.len; ++i) + { + padding.ptr[i] = (u_int8_t)(i + 1); + } +} + +METHOD(esp_packet_t, encrypt, status_t, + private_esp_packet_t *this, esp_context_t *esp_context, u_int32_t spi) +{ + chunk_t iv, icv, padding, payload, ciphertext, auth_data; + bio_writer_t *writer; + u_int32_t next_seqno; + size_t blocksize, plainlen; + crypter_t *crypter; + signer_t *signer; + rng_t *rng; + + this->packet->set_data(this->packet, chunk_empty); + + if (!esp_context->next_seqno(esp_context, &next_seqno)) + { + DBG1(DBG_ESP, "ESP encapsulation failed: sequence numbers cycled"); + return FAILED; + } + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_ESP, "ESP encryption failed: could not find RNG"); + return NOT_FOUND; + } + crypter = esp_context->get_crypter(esp_context); + signer = esp_context->get_signer(esp_context); + + blocksize = crypter->get_block_size(crypter); + iv.len = crypter->get_iv_size(crypter); + icv.len = signer->get_block_size(signer); + + /* plaintext = payload, padding, pad_length, next_header */ + payload = this->payload ? this->payload->get_encoding(this->payload) + : chunk_empty; + plainlen = payload.len + 2; + padding.len = blocksize - (plainlen % blocksize); + plainlen += padding.len; + + /* len = spi, seq, IV, plaintext, ICV */ + writer = bio_writer_create(2 * sizeof(u_int32_t) + iv.len + plainlen + + icv.len); + writer->write_uint32(writer, ntohl(spi)); + writer->write_uint32(writer, next_seqno); + + iv = writer->skip(writer, iv.len); + if (!rng->get_bytes(rng, iv.len, iv.ptr)) + { + DBG1(DBG_ESP, "ESP encryption failed: could not generate IV"); + writer->destroy(writer); + rng->destroy(rng); + return FAILED; + } + rng->destroy(rng); + + /* plain-/ciphertext will start here */ + ciphertext = writer->get_buf(writer); + ciphertext.ptr += ciphertext.len; + ciphertext.len = plainlen; + + writer->write_data(writer, payload); + + padding = writer->skip(writer, padding.len); + generate_padding(padding); + + writer->write_uint8(writer, padding.len); + writer->write_uint8(writer, this->next_header); + + DBG3(DBG_ESP, "ESP before encryption:\n payload = %B\n padding = %B\n " + "padding length = %hhu, next header = %hhu", &payload, &padding, + (u_int8_t)padding.len, this->next_header); + + /* encrypt the content inline */ + if (!crypter->encrypt(crypter, ciphertext, iv, NULL)) + { + DBG1(DBG_ESP, "ESP encryption failed"); + writer->destroy(writer); + return FAILED; + } + + /* calculate signature */ + auth_data = writer->get_buf(writer); + icv = writer->skip(writer, icv.len); + if (!signer->get_signature(signer, auth_data, icv.ptr)) + { + DBG1(DBG_ESP, "ESP encryption failed: signature generation failed"); + writer->destroy(writer); + return FAILED; + } + + DBG3(DBG_ESP, "ESP packet:\n SPI %.8x [seq %u]\n IV %B\n " + "encrypted %B\n ICV %B", ntohl(spi), next_seqno, &iv, + &ciphertext, &icv); + + this->packet->set_data(this->packet, writer->extract_buf(writer)); + writer->destroy(writer); + return SUCCESS; +} + +METHOD(esp_packet_t, get_next_header, u_int8_t, + private_esp_packet_t *this) +{ + return this->next_header; +} + +METHOD(esp_packet_t, get_payload, ip_packet_t*, + private_esp_packet_t *this) +{ + return this->payload; +} + +METHOD(esp_packet_t, extract_payload, ip_packet_t*, + private_esp_packet_t *this) +{ + ip_packet_t *payload; + + payload = this->payload; + this->payload = NULL; + return payload; +} + +METHOD2(esp_packet_t, packet_t, destroy, void, + private_esp_packet_t *this) +{ + DESTROY_IF(this->payload); + this->packet->destroy(this->packet); + free(this); +} + +static private_esp_packet_t *esp_packet_create_internal(packet_t *packet) +{ + private_esp_packet_t *this; + + INIT(this, + .public = { + .packet = { + .set_source = _set_source, + .get_source = _get_source, + .set_destination = _set_destination, + .get_destination = _get_destination, + .get_data = _get_data, + .set_data = _set_data, + .skip_bytes = _skip_bytes, + .clone = _clone, + .destroy = _destroy, + }, + .get_source = _get_source, + .get_destination = _get_destination, + .get_next_header = _get_next_header, + .parse_header = _parse_header, + .decrypt = _decrypt, + .encrypt = _encrypt, + .get_payload = _get_payload, + .extract_payload = _extract_payload, + .destroy = _destroy, + }, + .packet = packet, + .next_header = IPPROTO_NONE, + ); + return this; +} + +/** + * Described in header. + */ +esp_packet_t *esp_packet_create_from_packet(packet_t *packet) +{ + private_esp_packet_t *this; + + this = esp_packet_create_internal(packet); + + return &this->public; +} + +/** + * Described in header. + */ +esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, + ip_packet_t *payload) +{ + private_esp_packet_t *this; + packet_t *packet; + + packet = packet_create_from_data(src, dst, chunk_empty); + this = esp_packet_create_internal(packet); + this->payload = payload; + if (payload) + { + this->next_header = payload->get_version(payload) == 4 ? IPPROTO_IPIP + : IPPROTO_IPV6; + } + else + { + this->next_header = IPPROTO_NONE; + } + return &this->public; +} diff --git a/src/libipsec/esp_packet.h b/src/libipsec/esp_packet.h new file mode 100644 index 000000000..a1d1602c1 --- /dev/null +++ b/src/libipsec/esp_packet.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup esp_packet esp_packet + * @{ @ingroup libipsec + */ + +#ifndef ESP_PACKET_H_ +#define ESP_PACKET_H_ + +#include "ip_packet.h" +#include "esp_context.h" + +#include +#include +#include + +typedef struct esp_packet_t esp_packet_t; + +/** + * ESP packet + */ +struct esp_packet_t { + + /** + * Implements packet_t interface to access the raw ESP packet + */ + packet_t packet; + + /** + * Get the source address of this packet + * + * @return source host + */ + host_t *(*get_source)(esp_packet_t *this); + + /** + * Get the destination address of this packet + * + * @return destination host + */ + host_t *(*get_destination)(esp_packet_t *this); + + /** + * Parse the packet header before decryption. Tries to read the SPI + * from the packet to find a corresponding SA. + * + * @param spi parsed SPI, in network byte order + * @return TRUE when successful, FALSE otherwise (e.g. when the + * length of the packet is invalid) + */ + bool (*parse_header)(esp_packet_t *this, u_int32_t *spi); + + /** + * Authenticate and decrypt the packet. Also verifies the sequence number + * using the supplied ESP context and updates the anti-replay window. + * + * @param esp_context ESP context of corresponding inbound IPsec SA + * @return - SUCCESS if successfully authenticated, + * decrypted and parsed + * - PARSE_ERROR if the length of the packet or the + * padding is invalid + * - VERIFY_ERROR if the sequence number + * verification failed + * - FAILED if the ICV (MAC) check or the actual + * decryption failed + */ + status_t (*decrypt)(esp_packet_t *this, esp_context_t *esp_context); + + /** + * Encapsulate and encrypt the packet. The sequence number will be generated + * using the supplied ESP context. + * + * @param esp_context ESP context of corresponding outbound IPsec SA + * @param spi SPI value to use, in network byte order + * @return - SUCCESS if encrypted + * - FAILED if sequence number cycled or any of the + * cryptographic functions failed + * - NOT_FOUND if no suitable RNG could be found + */ + status_t (*encrypt)(esp_packet_t *this, esp_context_t *esp_context, + u_int32_t spi); + + /** + * Get the next header field of a packet. + * + * @note Packet has to be in the decrypted state. + * + * @return next header field + */ + u_int8_t (*get_next_header)(esp_packet_t *this); + + /** + * Get the plaintext payload of this packet. + * + * @return plaintext payload (internal data), + * NULL if not decrypted + */ + ip_packet_t *(*get_payload)(esp_packet_t *this); + + /** + * Extract the plaintext payload from this packet. + * + * @return plaintext payload (has to be destroyed), + * NULL if not decrypted + */ + ip_packet_t *(*extract_payload)(esp_packet_t *this); + + /** + * Destroy an esp_packet_t + */ + void (*destroy)(esp_packet_t *this); + +}; + +/** + * Create an ESP packet out of data from the wire. + * + * @param packet the packet data as received, gets owned + * @return esp_packet_t instance + */ +esp_packet_t *esp_packet_create_from_packet(packet_t *packet); + +/** + * Create an ESP packet from a plaintext payload + * + * @param src source address + * @param dst destination address + * @param payload plaintext payload, gets owned + * @return esp_packet_t instance + */ +esp_packet_t *esp_packet_create_from_payload(host_t *src, host_t *dst, + ip_packet_t *payload); + +#endif /** ESP_PACKET_H_ @}*/ + diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c new file mode 100644 index 000000000..096ca33a8 --- /dev/null +++ b/src/libipsec/ip_packet.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + + +#include "ip_packet.h" + +#include +#include + +#include +#include +#ifdef HAVE_NETINET_IP6_H +#include +#endif + +typedef struct private_ip_packet_t private_ip_packet_t; + +/** + * Private additions to ip_packet_t. + */ +struct private_ip_packet_t { + + /** + * Public members + */ + ip_packet_t public; + + /** + * Source address + */ + host_t *src; + + /** + * Destination address + */ + host_t *dst; + + /** + * IP packet + */ + chunk_t packet; + + /** + * IP version + */ + u_int8_t version; + + /** + * Protocol|Next Header field + */ + u_int8_t next_header; + +}; + +METHOD(ip_packet_t, get_version, u_int8_t, + private_ip_packet_t *this) +{ + return this->version; +} + +METHOD(ip_packet_t, get_source, host_t*, + private_ip_packet_t *this) +{ + return this->src; +} + +METHOD(ip_packet_t, get_destination, host_t*, + private_ip_packet_t *this) +{ + return this->dst; +} + +METHOD(ip_packet_t, get_encoding, chunk_t, + private_ip_packet_t *this) +{ + return this->packet; +} + +METHOD(ip_packet_t, get_next_header, u_int8_t, + private_ip_packet_t *this) +{ + return this->next_header; +} + +METHOD(ip_packet_t, clone, ip_packet_t*, + private_ip_packet_t *this) +{ + return ip_packet_create(this->packet); +} + +METHOD(ip_packet_t, destroy, void, + private_ip_packet_t *this) +{ + this->src->destroy(this->src); + this->dst->destroy(this->dst); + chunk_free(&this->packet); + free(this); +} + +/** + * Described in header. + */ +ip_packet_t *ip_packet_create(chunk_t packet) +{ + private_ip_packet_t *this; + u_int8_t version, next_header; + host_t *src, *dst; + + if (packet.len < 1) + { + DBG1(DBG_ESP, "IP packet too short"); + goto failed; + } + + version = (packet.ptr[0] & 0xf0) >> 4; + + switch (version) + { + case 4: + { + struct ip *ip; + + if (packet.len < sizeof(struct ip)) + { + DBG1(DBG_ESP, "IPv4 packet too short"); + goto failed; + } + ip = (struct ip*)packet.ptr; + src = host_create_from_chunk(AF_INET, + chunk_from_thing(ip->ip_src), 0); + dst = host_create_from_chunk(AF_INET, + chunk_from_thing(ip->ip_dst), 0); + next_header = ip->ip_p; + break; + } +#ifdef HAVE_NETINET_IP6_H + case 6: + { + struct ip6_hdr *ip; + + if (packet.len < sizeof(struct ip6_hdr)) + { + DBG1(DBG_ESP, "IPv6 packet too short"); + goto failed; + } + ip = (struct ip6_hdr*)packet.ptr; + src = host_create_from_chunk(AF_INET6, + chunk_from_thing(ip->ip6_src), 0); + dst = host_create_from_chunk(AF_INET6, + chunk_from_thing(ip->ip6_dst), 0); + next_header = ip->ip6_nxt; + break; + } +#endif /* HAVE_NETINET_IP6_H */ + default: + DBG1(DBG_ESP, "unsupported IP version"); + goto failed; + } + + INIT(this, + .public = { + .get_version = _get_version, + .get_source = _get_source, + .get_destination = _get_destination, + .get_next_header = _get_next_header, + .get_encoding = _get_encoding, + .clone = _clone, + .destroy = _destroy, + }, + .src = src, + .dst = dst, + .packet = packet, + .version = version, + .next_header = next_header, + ); + return &this->public; + +failed: + chunk_free(&packet); + return NULL; +} diff --git a/src/libipsec/ip_packet.h b/src/libipsec/ip_packet.h new file mode 100644 index 000000000..b4fc298ff --- /dev/null +++ b/src/libipsec/ip_packet.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ip_packet ip_packet + * @{ @ingroup libipsec + */ + +#ifndef IP_PACKET_H_ +#define IP_PACKET_H_ + +#include +#include +#include + +typedef struct ip_packet_t ip_packet_t; + +/** + * IP packet + */ +struct ip_packet_t { + + /** + * IP version of this packet + * + * @return ip version + */ + u_int8_t (*get_version)(ip_packet_t *this); + + /** + * Get the source address of this packet + * + * @return source host + */ + host_t *(*get_source)(ip_packet_t *this); + + /** + * Get the destination address of this packet + * + * @return destination host + */ + host_t *(*get_destination)(ip_packet_t *this); + + /** + * Get the protocol (IPv4) or next header (IPv6) field of this packet. + * + * @return protocol|next header field + */ + u_int8_t (*get_next_header)(ip_packet_t *this); + + /** + * Get the complete IP packet (including the header) + * + * @return IP packet (internal data) + */ + chunk_t (*get_encoding)(ip_packet_t *this); + + /** + * Clone the IP packet + * + * @return clone of the packet + */ + ip_packet_t *(*clone)(ip_packet_t *this); + + /** + * Destroy an ip_packet_t + */ + void (*destroy)(ip_packet_t *this); + +}; + +/** + * Create an IP packet out of data from the wire (or decapsulated from another + * packet). + * + * @note The raw IP packet gets either owned by the new object, or destroyed, + * if the data is invalid. + * + * @param packet the IP packet (including header), gets owned + * @return ip_packet_t instance, or NULL if invalid + */ +ip_packet_t *ip_packet_create(chunk_t packet); + +#endif /** IP_PACKET_H_ @}*/ diff --git a/src/libipsec/ipsec.c b/src/libipsec/ipsec.c new file mode 100644 index 000000000..50d9163ea --- /dev/null +++ b/src/libipsec/ipsec.c @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec.h" + +#include + +typedef struct private_ipsec_t private_ipsec_t; + +/** + * Private additions to ipsec_t. + */ +struct private_ipsec_t { + + /** + * Public members of ipsec_t. + */ + ipsec_t public; +}; + +/** + * Single instance of ipsec_t. + */ +ipsec_t *ipsec; + +/** + * Described in header. + */ +void libipsec_deinit() +{ + private_ipsec_t *this = (private_ipsec_t*)ipsec; + DESTROY_IF(this->public.processor); + DESTROY_IF(this->public.events); + DESTROY_IF(this->public.policies); + DESTROY_IF(this->public.sas); + free(this); + ipsec = NULL; +} + +/** + * Described in header. + */ +bool libipsec_init() +{ + private_ipsec_t *this; + + INIT(this); + ipsec = &this->public; + + if (lib->integrity && + !lib->integrity->check(lib->integrity, "libipsec", libipsec_init)) + { + DBG1(DBG_LIB, "integrity check of libipsec failed"); + return FALSE; + } + + this->public.sas = ipsec_sa_mgr_create(); + this->public.policies = ipsec_policy_mgr_create(); + this->public.events = ipsec_event_relay_create(); + this->public.processor = ipsec_processor_create(); + return TRUE; +} + diff --git a/src/libipsec/ipsec.h b/src/libipsec/ipsec.h new file mode 100644 index 000000000..7ee49432a --- /dev/null +++ b/src/libipsec/ipsec.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup libipsec libipsec + * + * @addtogroup libipsec + * @{ + */ + +#ifndef IPSEC_H_ +#define IPSEC_H_ + +#include "ipsec_sa_mgr.h" +#include "ipsec_policy_mgr.h" +#include "ipsec_event_relay.h" +#include "ipsec_processor.h" + +#include + +typedef struct ipsec_t ipsec_t; + +/** + * User space IPsec implementation. + */ +struct ipsec_t { + + /** + * IPsec SA manager instance + */ + ipsec_sa_mgr_t *sas; + + /** + * IPsec policy manager instance + */ + ipsec_policy_mgr_t *policies; + + /** + * Event relay instance + */ + ipsec_event_relay_t *events; + + /** + * IPsec processor instance + */ + ipsec_processor_t *processor; + +}; + +/** + * The single instance of ipsec_t. + * + * Set between calls to libipsec_init() and libipsec_deinit() calls. + */ +extern ipsec_t *ipsec; + +/** + * Initialize libipsec. + * + * @return FALSE if integrity check failed + */ +bool libipsec_init(); + +/** + * Deinitialize libipsec. + */ +void libipsec_deinit(); + +#endif /** IPSEC_H_ @}*/ diff --git a/src/libipsec/ipsec_event_listener.h b/src/libipsec/ipsec_event_listener.h new file mode 100644 index 000000000..c5c39b0f1 --- /dev/null +++ b/src/libipsec/ipsec_event_listener.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_event_listener ipsec_event_listener + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_EVENT_LISTENER_H_ +#define IPSEC_EVENT_LISTENER_H_ + +typedef struct ipsec_event_listener_t ipsec_event_listener_t; + +#include + +/** + * Listener interface for IPsec events + * + * All methods are optional. + */ +struct ipsec_event_listener_t { + + /** + * Called when the lifetime of an IPsec SA expired + * + * @param reqid reqid of the expired SA + * @param protocol protocol of the expired SA + * @param spi spi of the expired SA + * @param hard TRUE if this is a hard expire, FALSE otherwise + */ + void (*expire)(u_int32_t reqid, u_int8_t protocol, u_int32_t spi, + bool hard); + +}; + +#endif /** IPSEC_EVENT_LISTENER_H_ @}*/ diff --git a/src/libipsec/ipsec_event_relay.c b/src/libipsec/ipsec_event_relay.c new file mode 100644 index 000000000..34222258c --- /dev/null +++ b/src/libipsec/ipsec_event_relay.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec_event_relay.h" + +#include +#include +#include +#include +#include +#include + +typedef struct private_ipsec_event_relay_t private_ipsec_event_relay_t; + +/** + * Private additions to ipsec_event_relay_t. + */ +struct private_ipsec_event_relay_t { + + /** + * Public members + */ + ipsec_event_relay_t public; + + /** + * Registered listeners + */ + linked_list_t *listeners; + + /** + * Lock to safely access the list of listeners + */ + rwlock_t *lock; + + /** + * Blocking queue for events + */ + blocking_queue_t *queue; +}; + +/** + * Helper struct used to manage events in a queue + */ +typedef struct { + + /** + * Type of the event + */ + enum { + IPSEC_EVENT_EXPIRE, + } type; + + /** + * Reqid of the SA, if any + */ + u_int32_t reqid; + + /** + * SPI of the SA, if any + */ + u_int32_t spi; + + /** + * Additional data for specific event types + */ + union { + + struct { + /** Protocol of the SA */ + u_int8_t protocol; + /** TRUE in case of a hard expire */ + bool hard; + } expire; + + } data; + +} ipsec_event_t; + +/** + * Dequeue events and relay them to listeners + */ +static job_requeue_t handle_events(private_ipsec_event_relay_t *this) +{ + enumerator_t *enumerator; + ipsec_event_listener_t *current; + ipsec_event_t *event; + + event = this->queue->dequeue(this->queue); + + this->lock->read_lock(this->lock); + enumerator = this->listeners->create_enumerator(this->listeners); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + switch (event->type) + { + case IPSEC_EVENT_EXPIRE: + if (current->expire) + { + current->expire(event->reqid, event->data.expire.protocol, + event->spi, event->data.expire.hard); + } + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return JOB_REQUEUE_DIRECT; +} + +METHOD(ipsec_event_relay_t, expire, void, + private_ipsec_event_relay_t *this, u_int32_t reqid, u_int8_t protocol, + u_int32_t spi, bool hard) +{ + ipsec_event_t *event; + + INIT(event, + .type = IPSEC_EVENT_EXPIRE, + .reqid = reqid, + .spi = spi, + .data = { + .expire = { + .protocol = protocol, + .hard = hard, + }, + }, + ); + this->queue->enqueue(this->queue, event); +} + +METHOD(ipsec_event_relay_t, register_listener, void, + private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener) +{ + this->lock->write_lock(this->lock); + this->listeners->insert_last(this->listeners, listener); + this->lock->unlock(this->lock); +} + +METHOD(ipsec_event_relay_t, unregister_listener, void, + private_ipsec_event_relay_t *this, ipsec_event_listener_t *listener) +{ + this->lock->write_lock(this->lock); + this->listeners->remove(this->listeners, listener, NULL); + this->lock->unlock(this->lock); +} + +METHOD(ipsec_event_relay_t, destroy, void, + private_ipsec_event_relay_t *this) +{ + this->queue->destroy_function(this->queue, free); + this->listeners->destroy(this->listeners); + this->lock->destroy(this->lock); + free(this); +} + +/** + * Described in header. + */ +ipsec_event_relay_t *ipsec_event_relay_create() +{ + private_ipsec_event_relay_t *this; + + INIT(this, + .public = { + .expire = _expire, + .register_listener = _register_listener, + .unregister_listener = _unregister_listener, + .destroy = _destroy, + }, + .listeners = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .queue = blocking_queue_create(), + ); + + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)handle_events, this, + NULL, (callback_job_cancel_t)return_false)); + + return &this->public; +} diff --git a/src/libipsec/ipsec_event_relay.h b/src/libipsec/ipsec_event_relay.h new file mode 100644 index 000000000..c6935d546 --- /dev/null +++ b/src/libipsec/ipsec_event_relay.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_event_relay ipsec_event_relay + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_EVENT_RELAY_H_ +#define IPSEC_EVENT_RELAY_H_ + +#include "ipsec_event_listener.h" + +#include + +typedef struct ipsec_event_relay_t ipsec_event_relay_t; + +/** + * Event relay manager. + * + * Used to notify upper layers about changes + */ +struct ipsec_event_relay_t { + + /** + * Raise an expire event. + * + * @param reqid reqid of the expired IPsec SA + * @param protocol protocol (e.g ESP) of the expired SA + * @param spi SPI of the expired SA + * @param hard TRUE for a hard expire, FALSE otherwise + */ + void (*expire)(ipsec_event_relay_t *this, u_int32_t reqid, + u_int8_t protocol, u_int32_t spi, bool hard); + + /** + * Register a listener to events raised by this manager + * + * @param listener the listener to register + */ + void (*register_listener)(ipsec_event_relay_t *this, + ipsec_event_listener_t *listener); + + /** + * Unregister a listener + * + * @param listener the listener to unregister + */ + void (*unregister_listener)(ipsec_event_relay_t *this, + ipsec_event_listener_t *listener); + + /** + * Destroy an ipsec_event_relay_t + */ + void (*destroy)(ipsec_event_relay_t *this); + +}; + +/** + * Create an ipsec_event_relay_t instance + * + * @return IPsec event relay instance + */ +ipsec_event_relay_t *ipsec_event_relay_create(); + +#endif /** IPSEC_EVENT_RELAY_H_ @}*/ diff --git a/src/libipsec/ipsec_policy.c b/src/libipsec/ipsec_policy.c new file mode 100644 index 000000000..af8ea9f9d --- /dev/null +++ b/src/libipsec/ipsec_policy.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec_policy.h" + +#include + +typedef struct private_ipsec_policy_t private_ipsec_policy_t; + +/** + * Private additions to ipsec_policy_t. + */ +struct private_ipsec_policy_t { + + /** + * Public members + */ + ipsec_policy_t public; + + /** + * SA source address + */ + host_t *src; + + /** + * SA destination address + */ + host_t *dst; + + /** + * Source traffic selector + */ + traffic_selector_t *src_ts; + + /** + * Destination traffic selector + */ + traffic_selector_t *dst_ts; + + /** + * If any of the two TS has a protocol selector we cache it here + */ + u_int8_t protocol; + + /** + * Traffic direction + */ + policy_dir_t direction; + + /** + * Policy type + */ + policy_type_t type; + + /** + * SA configuration + */ + ipsec_sa_cfg_t sa; + + /** + * Mark + */ + mark_t mark; + + /** + * Policy priority + */ + policy_priority_t priority; + + /** + * Reference counter + */ + refcount_t refcount; + +}; + +METHOD(ipsec_policy_t, match, bool, + private_ipsec_policy_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, + mark_t mark, policy_priority_t priority) +{ + return (this->direction == direction && + this->priority == priority && + this->sa.reqid == reqid && + memeq(&this->mark, &mark, sizeof(mark_t)) && + this->src_ts->equals(this->src_ts, src_ts) && + this->dst_ts->equals(this->dst_ts, dst_ts)); +} + +METHOD(ipsec_policy_t, match_packet, bool, + private_ipsec_policy_t *this, ip_packet_t *packet) +{ + u_int8_t proto = packet->get_next_header(packet); + host_t *src = packet->get_source(packet), + *dst = packet->get_destination(packet); + + return (!this->protocol || this->protocol == proto) && + this->src_ts->includes(this->src_ts, src) && + this->dst_ts->includes(this->dst_ts, dst); +} + +METHOD(ipsec_policy_t, get_source_ts, traffic_selector_t*, + private_ipsec_policy_t *this) +{ + return this->src_ts; +} + +METHOD(ipsec_policy_t, get_destination_ts, traffic_selector_t*, + private_ipsec_policy_t *this) +{ + return this->dst_ts; +} + +METHOD(ipsec_policy_t, get_reqid, u_int32_t, + private_ipsec_policy_t *this) +{ + return this->sa.reqid; +} + +METHOD(ipsec_policy_t, get_direction, policy_dir_t, + private_ipsec_policy_t *this) +{ + return this->direction; +} + +METHOD(ipsec_policy_t, get_priority, policy_priority_t, + private_ipsec_policy_t *this) +{ + return this->priority; +} + +METHOD(ipsec_policy_t, get_type, policy_type_t, + private_ipsec_policy_t *this) +{ + return this->type; +} + +METHOD(ipsec_policy_t, get_ref, ipsec_policy_t*, + private_ipsec_policy_t *this) +{ + ref_get(&this->refcount); + return &this->public; +} + +METHOD(ipsec_policy_t, destroy, void, + private_ipsec_policy_t *this) +{ + if (ref_put(&this->refcount)) + { + this->src->destroy(this->src); + this->dst->destroy(this->dst); + this->src_ts->destroy(this->src_ts); + this->dst_ts->destroy(this->dst_ts); + free(this); + } +} + +/** + * Described in header. + */ +ipsec_policy_t *ipsec_policy_create(host_t *src, host_t *dst, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, + ipsec_sa_cfg_t *sa, mark_t mark, + policy_priority_t priority) +{ + private_ipsec_policy_t *this; + + INIT(this, + .public = { + .match = _match, + .match_packet = _match_packet, + .get_source_ts = _get_source_ts, + .get_destination_ts = _get_destination_ts, + .get_direction = _get_direction, + .get_priority = _get_priority, + .get_reqid = _get_reqid, + .get_type = _get_type, + .get_ref = _get_ref, + .destroy = _destroy, + }, + .src = src->clone(src), + .dst = dst->clone(dst), + .src_ts = src_ts->clone(src_ts), + .dst_ts = dst_ts->clone(dst_ts), + .protocol = max(src_ts->get_protocol(src_ts), + dst_ts->get_protocol(dst_ts)), + .direction = direction, + .type = type, + .sa = *sa, + .mark = mark, + .priority = priority, + .refcount = 1, + ); + + return &this->public; +} diff --git a/src/libipsec/ipsec_policy.h b/src/libipsec/ipsec_policy.h new file mode 100644 index 000000000..67ad0b0ed --- /dev/null +++ b/src/libipsec/ipsec_policy.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_policy ipsec_policy + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_POLICY_H +#define IPSEC_POLICY_H + +#include "ip_packet.h" + +#include +#include +#include +#include + +typedef struct ipsec_policy_t ipsec_policy_t; + +/** + * IPsec Policy + */ +struct ipsec_policy_t { + + /** + * Get the source traffic selector of this policy + * + * @return the source traffic selector + */ + traffic_selector_t *(*get_source_ts)(ipsec_policy_t *this); + + /** + * Get the destination traffic selector of this policy + * + * @return the destination traffic selector + */ + traffic_selector_t *(*get_destination_ts)(ipsec_policy_t *this); + + /** + * Get the direction of this policy + * + * @return direction + */ + policy_dir_t (*get_direction)(ipsec_policy_t *this); + + /** + * Get the priority of this policy + * + * @return priority + */ + policy_priority_t (*get_priority)(ipsec_policy_t *this); + + /** + * Get the type of this policy (e.g. IPsec) + * + * @return the policy type + */ + policy_type_t (*get_type)(ipsec_policy_t *this); + + /** + * Get the reqid associated to this policy + * + * @return the reqid + */ + u_int32_t (*get_reqid)(ipsec_policy_t *this); + + /** + * Get another reference to this policy + * + * @return additional reference to the policy + */ + ipsec_policy_t *(*get_ref)(ipsec_policy_t *this); + + /** + * Check if this policy matches all given parameters + * + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @param direction traffic direction + * @param reqid reqid of the policy + * @param mark mark for this policy + * @param prioirty policy priority + * @return TRUE if policy matches all parameters + */ + bool (*match)(ipsec_policy_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, + u_int32_t reqid, mark_t mark, policy_priority_t priority); + + /** + * Check if this policy matches the given IP packet + * + * @param packet IP packet + * @return TRUE if policy matches the packet + */ + bool (*match_packet)(ipsec_policy_t *this, ip_packet_t *packet); + + /** + * Destroy an ipsec_policy_t + */ + void (*destroy)(ipsec_policy_t *this); + +}; + +/** + * Create an ipsec_policy_t instance + * + * @param src source address of SA + * @param dst dest address of SA + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param type type of policy, POLICY_(IPSEC|PASS|DROP) + * @param sa details about the SA(s) tied to this policy + * @param mark mark for this policy + * @param priority priority of this policy + * @return ipsec policy instance + */ +ipsec_policy_t *ipsec_policy_create(host_t *src, host_t *dst, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, + ipsec_sa_cfg_t *sa, mark_t mark, + policy_priority_t priority); + +#endif /** IPSEC_POLICY_H @}*/ diff --git a/src/libipsec/ipsec_policy_mgr.c b/src/libipsec/ipsec_policy_mgr.c new file mode 100644 index 000000000..41ba792c3 --- /dev/null +++ b/src/libipsec/ipsec_policy_mgr.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec_policy_mgr.h" + +#include +#include +#include + +/** Base priority for installed policies */ +#define PRIO_BASE 512 + +typedef struct private_ipsec_policy_mgr_t private_ipsec_policy_mgr_t; + +/** + * Private additions to ipsec_policy_mgr_t. + */ +struct private_ipsec_policy_mgr_t { + + /** + * Public members of ipsec_policy_mgr_t. + */ + ipsec_policy_mgr_t public; + + /** + * Installed policies (ipsec_policy_entry_t*) + */ + linked_list_t *policies; + + /** + * Lock to safely access the list of policies + */ + rwlock_t *lock; + +}; + +/** + * Helper struct to store policies in a list sorted by the same pseudo-priority + * used by the NETLINK kernel interface. + */ +typedef struct { + + /** + * Priority used to sort policies + */ + u_int32_t priority; + + /** + * The policy + */ + ipsec_policy_t *policy; + +} ipsec_policy_entry_t; + +/** + * Calculate the pseudo-priority to sort policies. This is the same algorithm + * used by the NETLINK kernel interface (i.e. high priority -> low value). + */ +static u_int32_t calculate_priority(policy_priority_t policy_priority, + traffic_selector_t *src, + traffic_selector_t *dst) +{ + u_int32_t priority = PRIO_BASE; + u_int16_t port; + u_int8_t mask, proto; + host_t *net; + + switch (policy_priority) + { + case POLICY_PRIORITY_FALLBACK: + priority <<= 1; + /* fall-through */ + case POLICY_PRIORITY_ROUTED: + priority <<= 1; + /* fall-through */ + case POLICY_PRIORITY_DEFAULT: + break; + } + /* calculate priority based on selector size, small size = high prio */ + src->to_subnet(src, &net, &mask); + priority -= mask; + proto = src->get_protocol(src); + port = net->get_port(net); + net->destroy(net); + + dst->to_subnet(dst, &net, &mask); + priority -= mask; + proto = max(proto, dst->get_protocol(dst)); + port = max(port, net->get_port(net)); + net->destroy(net); + + priority <<= 2; /* make some room for the two flags */ + priority += port ? 0 : 2; + priority += proto ? 0 : 1; + return priority; +} + +/** + * Create a policy entry + */ +static ipsec_policy_entry_t *policy_entry_create(ipsec_policy_t *policy) +{ + ipsec_policy_entry_t *this; + + INIT(this, + .policy = policy, + .priority = calculate_priority(policy->get_priority(policy), + policy->get_source_ts(policy), + policy->get_destination_ts(policy)), + ); + return this; +} + +/** + * Destroy a policy entry + */ +static void policy_entry_destroy(ipsec_policy_entry_t *this) +{ + this->policy->destroy(this->policy); + free(this); +} + +METHOD(ipsec_policy_mgr_t, add_policy, status_t, + private_ipsec_policy_mgr_t *this, host_t *src, host_t *dst, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts, + policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, + policy_priority_t priority) +{ + enumerator_t *enumerator; + ipsec_policy_entry_t *entry, *current; + ipsec_policy_t *policy; + + if (type != POLICY_IPSEC || direction == POLICY_FWD) + { /* we ignore these policies as we currently have no use for them */ + return SUCCESS; + } + + DBG2(DBG_ESP, "adding policy %R === %R %N", src_ts, dst_ts, + policy_dir_names, direction); + + policy = ipsec_policy_create(src, dst, src_ts, dst_ts, direction, type, sa, + mark, priority); + entry = policy_entry_create(policy); + + this->lock->write_lock(this->lock); + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->priority >= entry->priority) + { + break; + } + } + this->policies->insert_before(this->policies, enumerator, entry); + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return SUCCESS; +} + +METHOD(ipsec_policy_mgr_t, del_policy, status_t, + private_ipsec_policy_mgr_t *this, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid, + mark_t mark, policy_priority_t policy_priority) +{ + enumerator_t *enumerator; + ipsec_policy_entry_t *current, *found = NULL; + u_int32_t priority; + + if (direction == POLICY_FWD) + { /* we ignore these policies as we currently have no use for them */ + return SUCCESS; + } + DBG2(DBG_ESP, "deleting policy %R === %R %N", src_ts, dst_ts, + policy_dir_names, direction); + + priority = calculate_priority(policy_priority, src_ts, dst_ts); + + this->lock->write_lock(this->lock); + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current->priority == priority && + current->policy->match(current->policy, src_ts, dst_ts, direction, + reqid, mark, policy_priority)) + { + this->policies->remove_at(this->policies, enumerator); + found = current; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + if (found) + { + policy_entry_destroy(found); + return SUCCESS; + } + return FAILED; +} + +METHOD(ipsec_policy_mgr_t, flush_policies, status_t, + private_ipsec_policy_mgr_t *this) +{ + ipsec_policy_entry_t *entry; + + DBG2(DBG_ESP, "flushing policies"); + + this->lock->write_lock(this->lock); + while (this->policies->remove_last(this->policies, + (void**)&entry) == SUCCESS) + { + policy_entry_destroy(entry); + } + this->lock->unlock(this->lock); + return SUCCESS; +} + +METHOD(ipsec_policy_mgr_t, find_by_packet, ipsec_policy_t*, + private_ipsec_policy_mgr_t *this, ip_packet_t *packet, bool inbound) +{ + enumerator_t *enumerator; + ipsec_policy_entry_t *current; + ipsec_policy_t *found = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->policies->create_enumerator(this->policies); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + ipsec_policy_t *policy = current->policy; + + if ((inbound == (policy->get_direction(policy) == POLICY_IN)) && + policy->match_packet(policy, packet)) + { + found = policy->get_ref(policy); + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return found; +} + +METHOD(ipsec_policy_mgr_t, destroy, void, + private_ipsec_policy_mgr_t *this) +{ + flush_policies(this); + this->policies->destroy(this->policies); + this->lock->destroy(this->lock); + free(this); +} + +/** + * Described in header. + */ +ipsec_policy_mgr_t *ipsec_policy_mgr_create() +{ + private_ipsec_policy_mgr_t *this; + + INIT(this, + .public = { + .add_policy = _add_policy, + .del_policy = _del_policy, + .flush_policies = _flush_policies, + .find_by_packet = _find_by_packet, + .destroy = _destroy, + }, + .policies = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libipsec/ipsec_policy_mgr.h b/src/libipsec/ipsec_policy_mgr.h new file mode 100644 index 000000000..d3ee1074f --- /dev/null +++ b/src/libipsec/ipsec_policy_mgr.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_policy_mgr ipsec_policy_mgr + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_POLICY_MGR_H_ +#define IPSEC_POLICY_MGR_H_ + +#include "ipsec_policy.h" +#include "ip_packet.h" + +#include +#include +#include +#include +#include + +typedef struct ipsec_policy_mgr_t ipsec_policy_mgr_t; + +/** + * IPsec policy manager + * + * The first methods are modeled after those in kernel_ipsec_t. + * + * @note Only policies of type POLICY_IPSEC are currently used, also policies + * with direction POLICY_FWD are ignored. Any packets that do not match an + * installed policy will be dropped. + */ +struct ipsec_policy_mgr_t { + + /** + * Add a policy + * + * A policy is always associated to an SA. Traffic which matches a + * policy is handled by the SA with the same reqid. + * + * @param src source address of SA + * @param dst dest address of SA + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param type type of policy, POLICY_(IPSEC|PASS|DROP) + * @param sa details about the SA(s) tied to this policy + * @param mark mark for this policy + * @param priority priority of this policy + * @return SUCCESS if operation completed + */ + status_t (*add_policy)(ipsec_policy_mgr_t *this, + host_t *src, host_t *dst, traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, policy_dir_t direction, + policy_type_t type, ipsec_sa_cfg_t *sa, mark_t mark, + policy_priority_t priority); + + /** + * Remove a policy + * + * @param src_ts traffic selector to match traffic source + * @param dst_ts traffic selector to match traffic dest + * @param direction direction of traffic, POLICY_(IN|OUT|FWD) + * @param reqid unique ID of the associated SA + * @param mark optional mark + * @param priority priority of the policy + * @return SUCCESS if operation completed + */ + status_t (*del_policy)(ipsec_policy_mgr_t *this, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts, + policy_dir_t direction, u_int32_t reqid, mark_t mark, + policy_priority_t priority); + + /** + * Flush all policies + * + * @return SUCCESS if operation completed + */ + status_t (*flush_policies)(ipsec_policy_mgr_t *this); + + /** + * Find the policy that matches the given IP packet best + * + * @param packet IP packet to match + * @param inbound TRUE for an inbound packet + * @return reference to the policy, or NULL if none found + */ + ipsec_policy_t *(*find_by_packet)(ipsec_policy_mgr_t *this, + ip_packet_t *packet, bool inbound); + + /** + * Destroy an ipsec_policy_mgr_t + */ + void (*destroy)(ipsec_policy_mgr_t *this); + +}; + +/** + * Create an ipsec_policy_mgr instance + * + * @return ipsec_policy_mgr + */ +ipsec_policy_mgr_t *ipsec_policy_mgr_create(); + +#endif /** IPSEC_POLICY_MGR_H_ @}*/ diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c new file mode 100644 index 000000000..a91d9e074 --- /dev/null +++ b/src/libipsec/ipsec_processor.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec.h" +#include "ipsec_processor.h" + +#include +#include +#include +#include +#include + +typedef struct private_ipsec_processor_t private_ipsec_processor_t; + +/** + * Private additions to ipsec_processor_t. + */ +struct private_ipsec_processor_t { + + /** + * Public members + */ + ipsec_processor_t public; + + /** + * Queue for inbound packets (esp_packet_t*) + */ + blocking_queue_t *inbound_queue; + + /** + * Queue for outbound packets (ip_packet_t*) + */ + blocking_queue_t *outbound_queue; + + /** + * Registered inbound callback + */ + struct { + ipsec_inbound_cb_t cb; + void *data; + } inbound; + + /** + * Registered outbound callback + */ + struct { + ipsec_outbound_cb_t cb; + void *data; + } outbound; + + /** + * Lock used to synchronize access to the callbacks + */ + rwlock_t *lock; +}; + +/** + * Deliver an inbound IP packet to the registered listener + */ +static void deliver_inbound(private_ipsec_processor_t *this, + esp_packet_t *packet) +{ + this->lock->read_lock(this->lock); + if (this->inbound.cb) + { + this->inbound.cb(this->inbound.data, packet->extract_payload(packet)); + } + else + { + DBG2(DBG_ESP, "no inbound callback registered, dropping packet"); + } + packet->destroy(packet); + this->lock->unlock(this->lock); +} + +/** + * Processes inbound packets + */ +static job_requeue_t process_inbound(private_ipsec_processor_t *this) +{ + esp_packet_t *packet; + ipsec_sa_t *sa; + u_int8_t next_header; + u_int32_t spi; + + packet = (esp_packet_t*)this->inbound_queue->dequeue(this->inbound_queue); + + if (!packet->parse_header(packet, &spi)) + { + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + + sa = ipsec->sas->checkout_by_spi(ipsec->sas, spi, + packet->get_destination(packet)); + if (!sa) + { + DBG2(DBG_ESP, "inbound ESP packet does not belong to an installed SA"); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + + if (!sa->is_inbound(sa)) + { + DBG1(DBG_ESP, "error: IPsec SA is not inbound"); + packet->destroy(packet); + ipsec->sas->checkin(ipsec->sas, sa); + return JOB_REQUEUE_DIRECT; + } + + if (packet->decrypt(packet, sa->get_esp_context(sa)) != SUCCESS) + { + ipsec->sas->checkin(ipsec->sas, sa); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + ipsec->sas->checkin(ipsec->sas, sa); + + next_header = packet->get_next_header(packet); + switch (next_header) + { + case IPPROTO_IPIP: + case IPPROTO_IPV6: + { + ipsec_policy_t *policy; + ip_packet_t *ip_packet; + + ip_packet = packet->get_payload(packet); + policy = ipsec->policies->find_by_packet(ipsec->policies, + ip_packet, TRUE); + if (policy) + { /* TODO-IPSEC: update policy/sa stats? */ + deliver_inbound(this, packet); + policy->destroy(policy); + break; + } + DBG1(DBG_ESP, "discarding inbound IP packet due to policy"); + /* no matching policy found, fall-through */ + } + case IPPROTO_NONE: + /* discard dummy packets */ + /* fall-through */ + default: + packet->destroy(packet); + break; + } + return JOB_REQUEUE_DIRECT; +} + +/** + * Send an ESP packet using the registered outbound callback + */ +static void send_outbound(private_ipsec_processor_t *this, + esp_packet_t *packet) +{ + this->lock->read_lock(this->lock); + if (this->outbound.cb) + { + this->outbound.cb(this->outbound.data, packet); + } + else + { + DBG2(DBG_ESP, "no outbound callback registered, dropping packet"); + packet->destroy(packet); + } + this->lock->unlock(this->lock); +} + +/** + * Processes outbound packets + */ +static job_requeue_t process_outbound(private_ipsec_processor_t *this) +{ + ipsec_policy_t *policy; + esp_packet_t *esp_packet; + ip_packet_t *packet; + ipsec_sa_t *sa; + host_t *src, *dst; + + packet = (ip_packet_t*)this->outbound_queue->dequeue(this->outbound_queue); + + policy = ipsec->policies->find_by_packet(ipsec->policies, packet, FALSE); + if (!policy) + { + DBG1(DBG_ESP, "no matching outbound IPsec policy for %H == %H", + packet->get_source(packet), packet->get_destination(packet)); + packet->destroy(packet); + return JOB_REQUEUE_DIRECT; + } + + sa = ipsec->sas->checkout_by_reqid(ipsec->sas, policy->get_reqid(policy), + FALSE); + if (!sa) + { /* TODO-IPSEC: send an acquire to uppper layer */ + DBG1(DBG_ESP, "could not find an outbound IPsec SA for reqid {%u}, " + "dropping packet", policy->get_reqid(policy)); + packet->destroy(packet); + policy->destroy(policy); + return JOB_REQUEUE_DIRECT; + } + src = sa->get_source(sa); + dst = sa->get_destination(sa); + esp_packet = esp_packet_create_from_payload(src->clone(src), + dst->clone(dst), packet); + if (esp_packet->encrypt(esp_packet, sa->get_esp_context(sa), + sa->get_spi(sa)) != SUCCESS) + { + ipsec->sas->checkin(ipsec->sas, sa); + esp_packet->destroy(esp_packet); + policy->destroy(policy); + return JOB_REQUEUE_DIRECT; + } + /* TODO-IPSEC: update policy/sa counters? */ + ipsec->sas->checkin(ipsec->sas, sa); + policy->destroy(policy); + send_outbound(this, esp_packet); + return JOB_REQUEUE_DIRECT; +} + +METHOD(ipsec_processor_t, queue_inbound, void, + private_ipsec_processor_t *this, esp_packet_t *packet) +{ + this->inbound_queue->enqueue(this->inbound_queue, packet); +} + +METHOD(ipsec_processor_t, queue_outbound, void, + private_ipsec_processor_t *this, ip_packet_t *packet) +{ + this->outbound_queue->enqueue(this->outbound_queue, packet); +} + +METHOD(ipsec_processor_t, register_inbound, void, + private_ipsec_processor_t *this, ipsec_inbound_cb_t cb, void *data) +{ + this->lock->write_lock(this->lock); + this->inbound.cb = cb; + this->inbound.data = data; + this->lock->unlock(this->lock); +} + +METHOD(ipsec_processor_t, unregister_inbound, void, + private_ipsec_processor_t *this, ipsec_inbound_cb_t cb) +{ + this->lock->write_lock(this->lock); + if (this->inbound.cb == cb) + { + this->inbound.cb = NULL; + } + this->lock->unlock(this->lock); +} + +METHOD(ipsec_processor_t, register_outbound, void, + private_ipsec_processor_t *this, ipsec_outbound_cb_t cb, void *data) +{ + this->lock->write_lock(this->lock); + this->outbound.cb = cb; + this->outbound.data = data; + this->lock->unlock(this->lock); +} + +METHOD(ipsec_processor_t, unregister_outbound, void, + private_ipsec_processor_t *this, ipsec_outbound_cb_t cb) +{ + this->lock->write_lock(this->lock); + if (this->outbound.cb == cb) + { + this->outbound.cb = NULL; + } + this->lock->unlock(this->lock); +} + +METHOD(ipsec_processor_t, destroy, void, + private_ipsec_processor_t *this) +{ + this->inbound_queue->destroy_offset(this->inbound_queue, + offsetof(esp_packet_t, destroy)); + this->outbound_queue->destroy_offset(this->outbound_queue, + offsetof(ip_packet_t, destroy)); + this->lock->destroy(this->lock); + free(this); +} + +/** + * Described in header. + */ +ipsec_processor_t *ipsec_processor_create() +{ + private_ipsec_processor_t *this; + + INIT(this, + .public = { + .queue_inbound = _queue_inbound, + .queue_outbound = _queue_outbound, + .register_inbound = _register_inbound, + .unregister_inbound = _unregister_inbound, + .register_outbound = _register_outbound, + .unregister_outbound = _unregister_outbound, + .destroy = _destroy, + }, + .inbound_queue = blocking_queue_create(), + .outbound_queue = blocking_queue_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)process_inbound, this, + NULL, (callback_job_cancel_t)return_false)); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create((callback_job_cb_t)process_outbound, this, + NULL, (callback_job_cancel_t)return_false)); + return &this->public; +} diff --git a/src/libipsec/ipsec_processor.h b/src/libipsec/ipsec_processor.h new file mode 100644 index 000000000..0a409828b --- /dev/null +++ b/src/libipsec/ipsec_processor.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_processor ipsec_processor + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_PROCESSOR_H_ +#define IPSEC_PROCESSOR_H_ + +#include "ip_packet.h" +#include "esp_packet.h" + +typedef struct ipsec_processor_t ipsec_processor_t; + +/** + * Callback called to deliver an inbound plaintext packet. + * + * @param data data supplied during registration of the callback + * @param packet plaintext IP packet to deliver + */ +typedef void (*ipsec_inbound_cb_t)(void *data, ip_packet_t *packet); + +/** + * Callback called to send an ESP packet. + * + * @note The ESP packet currently comes without IP header (and without UDP + * header in case of UDP encapsulation) + * + * @param data data supplied during registration of the callback + * @param packet ESP packet to send + */ +typedef void (*ipsec_outbound_cb_t)(void *data, esp_packet_t *packet); + +/** + * IPsec processor + */ +struct ipsec_processor_t { + + /** + * Queue an inbound ESP packet for processing. + * + * @param packet the ESP packet to process + */ + void (*queue_inbound)(ipsec_processor_t *this, esp_packet_t *packet); + + /** + * Queue an outbound plaintext IP packet for processing. + * + * @param packet the plaintext IP packet + */ + void (*queue_outbound)(ipsec_processor_t *this, ip_packet_t *packet); + + /** + * Register the callback used to deliver inbound plaintext packets. + * + * @param cb the inbound callback function + * @param data optional data provided to callback + */ + void (*register_inbound)(ipsec_processor_t *this, ipsec_inbound_cb_t cb, + void *data); + + /** + * Unregister a previously registered inbound callback. + * + * @param cb previously registered callback function + */ + void (*unregister_inbound)(ipsec_processor_t *this, + ipsec_inbound_cb_t cb); + + /** + * Register the callback used to send outbound ESP packets. + * + * @param cb the outbound callback function + * @param data optional data provided to callback + */ + void (*register_outbound)(ipsec_processor_t *this, ipsec_outbound_cb_t cb, + void *data); + + /** + * Unregister a previously registered outbound callback. + * + * @param cb previously registered callback function + */ + void (*unregister_outbound)(ipsec_processor_t *this, + ipsec_outbound_cb_t cb); + + /** + * Destroy an ipsec_processor_t. + */ + void (*destroy)(ipsec_processor_t *this); + +}; + +/** + * Create an ipsec_processor_t instance + * + * @return IPsec processor instance + */ +ipsec_processor_t *ipsec_processor_create(); + +#endif /** IPSEC_PROCESSOR_H_ @}*/ diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c new file mode 100644 index 000000000..cccd16404 --- /dev/null +++ b/src/libipsec/ipsec_sa.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec_sa.h" + +#include +#include + +typedef struct private_ipsec_sa_t private_ipsec_sa_t; + +/** + * Private additions to ipsec_sa_t. + */ +struct private_ipsec_sa_t { + + /** + * Public members + */ + ipsec_sa_t public; + + /** + * SPI of this SA + */ + u_int32_t spi; + + /** + * Source address + */ + host_t *src; + + /** + * Destination address + */ + host_t *dst; + + /** + * Protocol + */ + u_int8_t protocol; + + /** + * Reqid of this SA + */ + u_int32_t reqid; + + /** + * Lifetime configuration + */ + lifetime_cfg_t lifetime; + + /** + * IPsec mode + */ + ipsec_mode_t mode; + + /** + * TRUE if extended sequence numbers are used + */ + bool esn; + + /** + * TRUE if this is an inbound SA + */ + bool inbound; + + /** + * ESP context + */ + esp_context_t *esp_context; +}; + +METHOD(ipsec_sa_t, get_source, host_t*, + private_ipsec_sa_t *this) +{ + return this->src; +} + +METHOD(ipsec_sa_t, get_destination, host_t*, + private_ipsec_sa_t *this) +{ + return this->dst; +} + +METHOD(ipsec_sa_t, get_spi, u_int32_t, + private_ipsec_sa_t *this) +{ + return this->spi; +} + +METHOD(ipsec_sa_t, get_reqid, u_int32_t, + private_ipsec_sa_t *this) +{ + return this->reqid; +} + +METHOD(ipsec_sa_t, get_protocol, u_int8_t, + private_ipsec_sa_t *this) +{ + return this->protocol; +} + +METHOD(ipsec_sa_t, get_lifetime, lifetime_cfg_t*, + private_ipsec_sa_t *this) +{ + return &this->lifetime; +} + +METHOD(ipsec_sa_t, is_inbound, bool, + private_ipsec_sa_t *this) +{ + return this->inbound; +} + +METHOD(ipsec_sa_t, get_esp_context, esp_context_t*, + private_ipsec_sa_t *this) +{ + return this->esp_context; +} + +METHOD(ipsec_sa_t, match_by_spi_dst, bool, + private_ipsec_sa_t *this, u_int32_t spi, host_t *dst) +{ + return this->spi == spi && this->dst->ip_equals(this->dst, dst); +} + +METHOD(ipsec_sa_t, match_by_spi_src_dst, bool, + private_ipsec_sa_t *this, u_int32_t spi, host_t *src, host_t *dst) +{ + return this->spi == spi && this->src->ip_equals(this->src, src) && + this->dst->ip_equals(this->dst, dst); +} + +METHOD(ipsec_sa_t, match_by_reqid, bool, + private_ipsec_sa_t *this, u_int32_t reqid, bool inbound) +{ + return this->reqid == reqid && this->inbound == inbound; +} + +METHOD(ipsec_sa_t, destroy, void, + private_ipsec_sa_t *this) +{ + this->src->destroy(this->src); + this->dst->destroy(this->dst); + DESTROY_IF(this->esp_context); + free(this); +} + +/** + * Described in header. + */ +ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, + lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, + u_int16_t ipcomp, u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + private_ipsec_sa_t *this; + + if (protocol != IPPROTO_ESP) + { + DBG1(DBG_ESP, " IPsec SA: protocol not supported"); + return NULL; + } + if (!encap) + { + DBG1(DBG_ESP, " IPsec SA: only UDP encapsulation is supported"); + return NULL; + } + if (esn) + { + DBG1(DBG_ESP, " IPsec SA: ESN not supported"); + return NULL; + } + if (ipcomp != IPCOMP_NONE) + { + DBG1(DBG_ESP, " IPsec SA: compression not supported"); + return NULL; + } + if (mode != MODE_TUNNEL) + { + DBG1(DBG_ESP, " IPsec SA: unsupported mode"); + return NULL; + } + + INIT(this, + .public = { + .destroy = _destroy, + .get_source = _get_source, + .get_destination = _get_destination, + .get_spi = _get_spi, + .get_reqid = _get_reqid, + .get_protocol = _get_protocol, + .get_lifetime = _get_lifetime, + .is_inbound = _is_inbound, + .match_by_spi_dst = _match_by_spi_dst, + .match_by_spi_src_dst = _match_by_spi_src_dst, + .match_by_reqid = _match_by_reqid, + .get_esp_context = _get_esp_context, + }, + .spi = spi, + .src = src->clone(src), + .dst = dst->clone(dst), + .lifetime = *lifetime, + .protocol = protocol, + .reqid = reqid, + .mode = mode, + .esn = esn, + .inbound = inbound, + ); + + this->esp_context = esp_context_create(enc_alg, enc_key, int_alg, int_key, + inbound); + if (!this->esp_context) + { + destroy(this); + return NULL; + } + return &this->public; +} diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h new file mode 100644 index 000000000..5fd03b6e4 --- /dev/null +++ b/src/libipsec/ipsec_sa.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_sa ipsec_sa + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_SA_H_ +#define IPSEC_SA_H_ + +#include "esp_context.h" + +#include +#include +#include +#include + +typedef struct ipsec_sa_t ipsec_sa_t; + +/** + * IPsec Security Association (SA) + */ +struct ipsec_sa_t { + + /** + * Get the source address for this SA + * + * @return source address of this SA + */ + host_t *(*get_source)(ipsec_sa_t *this); + + /** + * Get the destination address for this SA + * + * @return destination address of this SA + */ + host_t *(*get_destination)(ipsec_sa_t *this); + + /** + * Get the SPI for this SA + * + * @return SPI of this SA + */ + u_int32_t (*get_spi)(ipsec_sa_t *this); + + /** + * Get the reqid of this SA + * + * @return reqid of this SA + */ + u_int32_t (*get_reqid)(ipsec_sa_t *this); + + /** + * Get the protocol (e.g. IPPROTO_ESP) of this SA + * + * @return protocol of this SA + */ + u_int8_t (*get_protocol)(ipsec_sa_t *this); + + /** + * Returns whether this SA is inbound or outbound + * + * @return TRUE if inbound, FALSE if outbound + */ + bool (*is_inbound)(ipsec_sa_t *this); + + /** + * Get the lifetime information for this SA + * Note that this information is always relative to the time when the + * SA was installed (i.e. it is not adjusted over time) + * + * @return lifetime of this SA + */ + lifetime_cfg_t *(*get_lifetime)(ipsec_sa_t *this); + + /** + * Get the ESP context for this SA + * + * @return ESP context of this SA + */ + esp_context_t *(*get_esp_context)(ipsec_sa_t *this); + + /** + * Check if this SA matches all given parameters + * + * @param spi SPI + * @param dst destination address + * @return TRUE if this SA matches all parameters, FALSE otherwise + */ + bool (*match_by_spi_dst)(ipsec_sa_t *this, u_int32_t spi, host_t *dst); + + /** + * Check if this SA matches all given parameters + * + * @param spi SPI + * @param src source address + * @param dst destination address + * @return TRUE if this SA matches all parameters, FALSE otherwise + */ + bool (*match_by_spi_src_dst)(ipsec_sa_t *this, u_int32_t spi, host_t *src, + host_t *dst); + + /** + * Check if this SA matches all given parameters + * + * @param reqid reqid + * @param inbound TRUE for inbound SA, FALSE for outbound + * @return TRUE if this SA matches all parameters, FALSE otherwise + */ + bool (*match_by_reqid)(ipsec_sa_t *this, u_int32_t reqid, bool inbound); + + /** + * Destroy an ipsec_sa_t + */ + void (*destroy)(ipsec_sa_t *this); + +}; + +/** + * Create an ipsec_sa_t instance + * + * @param spi SPI for this SA + * @param src source address for this SA (gets cloned) + * @param dst destination address for this SA (gets cloned) + * @param protocol protocol for this SA (only ESP is supported) + * @param reqid reqid for this SA + * @param mark mark for this SA (ignored) + * @param tfc Traffic Flow Confidentiality (currently not supported) + * @param lifetime lifetime for this SA + * @param enc_alg encryption algorithm for this SA + * @param enc_key encryption key for this SA + * @param int_alg integrity protection algorithm + * @param int_key integrity protection key + * @param mode mode for this SA (only tunnel mode is supported) + * @param ipcomp IPcomp transform (not supported, use IPCOMP_NONE) + * @param cpi CPI for IPcomp (ignored) + * @param encap enable UDP encapsulation (must be TRUE) + * @param esn Extended Sequence Numbers (currently not supported) + * @param inbound TRUE if this is an inbound SA, FALSE otherwise + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @return the IPsec SA, or NULL if the creation failed + */ +ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, mark_t mark, + u_int32_t tfc, lifetime_cfg_t *lifetime, + u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, + ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi, + bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, + traffic_selector_t *dst_ts); + +#endif /** IPSEC_SA_H_ @}*/ diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c new file mode 100644 index 000000000..e42c77aa5 --- /dev/null +++ b/src/libipsec/ipsec_sa_mgr.c @@ -0,0 +1,626 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec.h" +#include "ipsec_sa_mgr.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_ipsec_sa_mgr_t private_ipsec_sa_mgr_t; + +/** + * Private additions to ipsec_sa_mgr_t. + */ +struct private_ipsec_sa_mgr_t { + + /** + * Public members of ipsec_sa_mgr_t. + */ + ipsec_sa_mgr_t public; + + /** + * Installed SAs + */ + linked_list_t *sas; + + /** + * SPIs allocated using get_spi() + */ + hashtable_t *allocated_spis; + + /** + * Mutex used to synchronize access to the SA manager + */ + mutex_t *mutex; + + /** + * RNG used to generate SPIs + */ + rng_t *rng; +}; + +/** + * Struct to keep track of locked IPsec SAs + */ +typedef struct { + + /** + * IPsec SA + */ + ipsec_sa_t *sa; + + /** + * Set if this SA is currently in use by a thread + */ + bool locked; + + /** + * Condvar used by threads to wait for this entry + */ + condvar_t *condvar; + + /** + * Number of threads waiting for this entry + */ + u_int waiting_threads; + + /** + * Set if this entry is awaiting deletion + */ + bool awaits_deletion; + +} ipsec_sa_entry_t; + +/** + * Helper struct for expiration events + */ +typedef struct { + + /** + * IPsec SA manager + */ + private_ipsec_sa_mgr_t *manager; + + /** + * Entry that expired + */ + ipsec_sa_entry_t *entry; + + /** + * 0 if this is a hard expire, otherwise the offset in s (soft->hard) + */ + u_int32_t hard_offset; + +} ipsec_sa_expired_t; + +/* + * Used for the hash table of allocated SPIs + */ +static bool spi_equals(u_int32_t *spi, u_int32_t *other_spi) +{ + return *spi == *other_spi; +} + +static u_int spi_hash(u_int32_t *spi) +{ + return chunk_hash(chunk_from_thing(*spi)); +} + +/** + * Create an SA entry + */ +static ipsec_sa_entry_t *create_entry(ipsec_sa_t *sa) +{ + ipsec_sa_entry_t *this; + + INIT(this, + .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + .sa = sa, + ); + return this; +} + +/** + * Destroy an SA entry + */ +static void destroy_entry(ipsec_sa_entry_t *entry) +{ + entry->condvar->destroy(entry->condvar); + entry->sa->destroy(entry->sa); + free(entry); +} + +/** + * Makes sure an entry is safe to remove + * Must be called with this->mutex held. + * + * @return TRUE if entry can be removed, FALSE if entry is already +* being removed by another thread + */ +static bool wait_remove_entry(private_ipsec_sa_mgr_t *this, + ipsec_sa_entry_t *entry) +{ + if (entry->awaits_deletion) + { + /* this will be deleted by another thread already */ + return FALSE; + } + entry->awaits_deletion = TRUE; + while (entry->locked) + { + entry->condvar->wait(entry->condvar, this->mutex); + } + while (entry->waiting_threads > 0) + { + entry->condvar->broadcast(entry->condvar); + entry->condvar->wait(entry->condvar, this->mutex); + } + return TRUE; +} + +/** + * Waits until an is available and then locks it. + * Must only be called with this->mutex held + */ +static bool wait_for_entry(private_ipsec_sa_mgr_t *this, + ipsec_sa_entry_t *entry) +{ + while (entry->locked && !entry->awaits_deletion) + { + entry->waiting_threads++; + entry->condvar->wait(entry->condvar, this->mutex); + entry->waiting_threads--; + } + if (entry->awaits_deletion) + { + /* others may still be waiting, */ + entry->condvar->signal(entry->condvar); + return FALSE; + } + entry->locked = TRUE; + return TRUE; +} + +/** + * Flushes all entries + * Must be called with this->mutex held. + */ +static void flush_entries(private_ipsec_sa_mgr_t *this) +{ + ipsec_sa_entry_t *current; + enumerator_t *enumerator; + + DBG2(DBG_ESP, "flushing SAD"); + + enumerator = this->sas->create_enumerator(this->sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (wait_remove_entry(this, current)) + { + this->sas->remove_at(this->sas, enumerator); + destroy_entry(current); + } + } + enumerator->destroy(enumerator); +} + +/* + * Different match functions to find SAs in the linked list + */ +static bool match_entry_by_ptr(ipsec_sa_entry_t *item, ipsec_sa_entry_t *entry) +{ + return item == entry; +} + +static bool match_entry_by_sa_ptr(ipsec_sa_entry_t *item, ipsec_sa_t *sa) +{ + return item->sa == sa; +} + +static bool match_entry_by_spi_inbound(ipsec_sa_entry_t *item, u_int32_t spi, + bool inbound) +{ + return item->sa->get_spi(item->sa) == spi && + item->sa->is_inbound(item->sa) == inbound; +} + +static bool match_entry_by_spi_src_dst(ipsec_sa_entry_t *item, u_int32_t spi, + host_t *src, host_t *dst) +{ + return item->sa->match_by_spi_src_dst(item->sa, spi, src, dst); +} + +static bool match_entry_by_reqid_inbound(ipsec_sa_entry_t *item, + u_int32_t reqid, bool inbound) +{ + return item->sa->match_by_reqid(item->sa, reqid, inbound); +} + +static bool match_entry_by_spi_dst(ipsec_sa_entry_t *item, u_int32_t spi, + host_t *dst) +{ + return item->sa->match_by_spi_dst(item->sa, spi, dst); +} + +/** + * Remove an entry + */ +static bool remove_entry(private_ipsec_sa_mgr_t *this, ipsec_sa_entry_t *entry) +{ + ipsec_sa_entry_t *current; + enumerator_t *enumerator; + bool removed = FALSE; + + enumerator = this->sas->create_enumerator(this->sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current == entry) + { + if (wait_remove_entry(this, current)) + { + this->sas->remove_at(this->sas, enumerator); + removed = TRUE; + } + break; + } + } + enumerator->destroy(enumerator); + return removed; +} + +/** + * Callback for expiration events + */ +static job_requeue_t sa_expired(ipsec_sa_expired_t *expired) +{ + private_ipsec_sa_mgr_t *this = expired->manager; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr, + NULL, expired->entry) == SUCCESS) + { + u_int32_t hard_offset = expired->hard_offset; + ipsec_sa_t *sa = expired->entry->sa; + + ipsec->events->expire(ipsec->events, sa->get_reqid(sa), + sa->get_protocol(sa), sa->get_spi(sa), + hard_offset == 0); + if (hard_offset) + { /* soft limit reached, schedule hard expire */ + expired->hard_offset = 0; + this->mutex->unlock(this->mutex); + return JOB_RESCHEDULE(hard_offset); + } + /* hard limit reached */ + if (remove_entry(this, expired->entry)) + { + destroy_entry(expired->entry); + } + } + this->mutex->unlock(this->mutex); + return JOB_REQUEUE_NONE; +} + +/** + * Schedule a job to handle IPsec SA expiration + */ +static void schedule_expiration(private_ipsec_sa_mgr_t *this, + ipsec_sa_entry_t *entry) +{ + lifetime_cfg_t *lifetime = entry->sa->get_lifetime(entry->sa); + ipsec_sa_expired_t *expired; + callback_job_t *job; + u_int32_t timeout; + + INIT(expired, + .manager = this, + .entry = entry, + ); + + /* schedule a rekey first, a hard timeout will be scheduled then, if any */ + expired->hard_offset = lifetime->time.life - lifetime->time.rekey; + timeout = lifetime->time.rekey; + + if (lifetime->time.life <= lifetime->time.rekey || + lifetime->time.rekey == 0) + { /* no rekey, schedule hard timeout */ + expired->hard_offset = 0; + timeout = lifetime->time.life; + } + + job = callback_job_create((callback_job_cb_t)sa_expired, expired, + (callback_job_cleanup_t)free, NULL); + lib->scheduler->schedule_job(lib->scheduler, (job_t*)job, timeout); +} + +/** + * Remove all allocated SPIs + */ +static void flush_allocated_spis(private_ipsec_sa_mgr_t *this) +{ + enumerator_t *enumerator; + u_int32_t *current; + + DBG2(DBG_ESP, "flushing allocated SPIs"); + enumerator = this->allocated_spis->create_enumerator(this->allocated_spis); + while (enumerator->enumerate(enumerator, NULL, (void**)¤t)) + { + this->allocated_spis->remove_at(this->allocated_spis, enumerator); + DBG2(DBG_ESP, " removed allocated SPI %.8x", ntohl(*current)); + free(current); + } + enumerator->destroy(enumerator); +} + +/** + * Pre-allocate an SPI for an inbound SA + */ +static bool allocate_spi(private_ipsec_sa_mgr_t *this, u_int32_t spi) +{ + u_int32_t *spi_alloc; + + if (this->allocated_spis->get(this->allocated_spis, &spi) || + this->sas->find_first(this->sas, (void*)match_entry_by_spi_inbound, + NULL, spi, TRUE) == SUCCESS) + { + return FALSE; + } + spi_alloc = malloc_thing(u_int32_t); + *spi_alloc = spi; + this->allocated_spis->put(this->allocated_spis, spi_alloc, spi_alloc); + return TRUE; +} + +METHOD(ipsec_sa_mgr_t, get_spi, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int8_t protocol, + u_int32_t reqid, u_int32_t *spi) +{ + u_int32_t spi_new; + + DBG2(DBG_ESP, "allocating SPI for reqid {%u}", reqid); + + this->mutex->lock(this->mutex); + if (!this->rng) + { + this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!this->rng) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to create RNG for SPI generation"); + return FAILED; + } + } + + do + { + if (!this->rng->get_bytes(this->rng, sizeof(spi_new), + (u_int8_t*)&spi_new)) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to allocate SPI for reqid {%u}", reqid); + return FAILED; + } + /* make sure the SPI is valid (not in range 0-255) */ + spi_new |= 0x00000100; + spi_new = htonl(spi_new); + } + while (!allocate_spi(this, spi_new)); + this->mutex->unlock(this->mutex); + + *spi = spi_new; + + DBG2(DBG_ESP, "allocated SPI %.8x for reqid {%u}", ntohl(*spi), reqid); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, add_sa, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc, + lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key, + u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts) +{ + ipsec_sa_entry_t *entry; + ipsec_sa_t *sa_new; + + DBG2(DBG_ESP, "adding SAD entry with SPI %.8x and reqid {%u}", + ntohl(spi), reqid); + DBG2(DBG_ESP, " using encryption algorithm %N with key size %d", + encryption_algorithm_names, enc_alg, enc_key.len * 8); + DBG2(DBG_ESP, " using integrity algorithm %N with key size %d", + integrity_algorithm_names, int_alg, int_key.len * 8); + + sa_new = ipsec_sa_create(spi, src, dst, protocol, reqid, mark, tfc, + lifetime, enc_alg, enc_key, int_alg, int_key, mode, + ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts); + if (!sa_new) + { + DBG1(DBG_ESP, "failed to create SAD entry"); + return FAILED; + } + + this->mutex->lock(this->mutex); + + if (inbound) + { /* remove any pre-allocated SPIs */ + u_int32_t *spi_alloc; + + spi_alloc = this->allocated_spis->remove(this->allocated_spis, &spi); + free(spi_alloc); + } + + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, + NULL, spi, src, dst) == SUCCESS) + { + this->mutex->unlock(this->mutex); + DBG1(DBG_ESP, "failed to install SAD entry: already installed"); + sa_new->destroy(sa_new); + return FAILED; + } + + entry = create_entry(sa_new); + schedule_expiration(this, entry); + this->sas->insert_last(this->sas, entry); + + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, del_sa, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, + u_int8_t protocol, u_int16_t cpi, mark_t mark) +{ + ipsec_sa_entry_t *current, *found = NULL; + enumerator_t *enumerator; + + this->mutex->lock(this->mutex); + enumerator = this->sas->create_enumerator(this->sas); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (match_entry_by_spi_src_dst(current, spi, src, dst)) + { + if (wait_remove_entry(this, current)) + { + this->sas->remove_at(this->sas, enumerator); + found = current; + } + break; + } + } + enumerator->destroy(enumerator); + this->mutex->unlock(this->mutex); + + if (found) + { + DBG2(DBG_ESP, "deleted %sbound SAD entry with SPI %.8x", + found->sa->is_inbound(found->sa) ? "in" : "out", ntohl(spi)); + destroy_entry(found); + return SUCCESS; + } + return FAILED; +} + +METHOD(ipsec_sa_mgr_t, checkout_by_reqid, ipsec_sa_t*, + private_ipsec_sa_mgr_t *this, u_int32_t reqid, bool inbound) +{ + ipsec_sa_entry_t *entry; + ipsec_sa_t *sa = NULL; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_reqid_inbound, + (void**)&entry, reqid, inbound) == SUCCESS && + wait_for_entry(this, entry)) + { + sa = entry->sa; + } + this->mutex->unlock(this->mutex); + return sa; +} + +METHOD(ipsec_sa_mgr_t, checkout_by_spi, ipsec_sa_t*, + private_ipsec_sa_mgr_t *this, u_int32_t spi, host_t *dst) +{ + ipsec_sa_entry_t *entry; + ipsec_sa_t *sa = NULL; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_dst, + (void**)&entry, spi, dst) == SUCCESS && + wait_for_entry(this, entry)) + { + sa = entry->sa; + } + this->mutex->unlock(this->mutex); + return sa; +} + +METHOD(ipsec_sa_mgr_t, checkin, void, + private_ipsec_sa_mgr_t *this, ipsec_sa_t *sa) +{ + ipsec_sa_entry_t *entry; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_sa_ptr, + (void**)&entry, sa) == SUCCESS) + { + if (entry->locked) + { + entry->locked = FALSE; + entry->condvar->signal(entry->condvar); + } + } + this->mutex->unlock(this->mutex); +} + +METHOD(ipsec_sa_mgr_t, flush_sas, status_t, + private_ipsec_sa_mgr_t *this) +{ + this->mutex->lock(this->mutex); + flush_entries(this); + this->mutex->unlock(this->mutex); + return SUCCESS; +} + +METHOD(ipsec_sa_mgr_t, destroy, void, + private_ipsec_sa_mgr_t *this) +{ + this->mutex->lock(this->mutex); + flush_entries(this); + flush_allocated_spis(this); + this->mutex->unlock(this->mutex); + + this->allocated_spis->destroy(this->allocated_spis); + this->sas->destroy(this->sas); + + this->mutex->destroy(this->mutex); + DESTROY_IF(this->rng); + free(this); +} + +/** + * Described in header. + */ +ipsec_sa_mgr_t *ipsec_sa_mgr_create() +{ + private_ipsec_sa_mgr_t *this; + + INIT(this, + .public = { + .get_spi = _get_spi, + .add_sa = _add_sa, + .del_sa = _del_sa, + .checkout_by_spi = _checkout_by_spi, + .checkout_by_reqid = _checkout_by_reqid, + .checkin = _checkin, + .flush_sas = _flush_sas, + .destroy = _destroy, + }, + .sas = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .allocated_spis = hashtable_create((hashtable_hash_t)spi_hash, + (hashtable_equals_t)spi_equals, 16), + ); + + return &this->public; +} diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h new file mode 100644 index 000000000..303b36f0e --- /dev/null +++ b/src/libipsec/ipsec_sa_mgr.h @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_sa_mgr ipsec_sa_mgr + * @{ @ingroup libipsec + */ + +#ifndef IPSEC_SA_MGR_H_ +#define IPSEC_SA_MGR_H_ + +#include "ipsec_sa.h" + +#include +#include +#include +#include + +typedef struct ipsec_sa_mgr_t ipsec_sa_mgr_t; + +/** + * IPsec SA manager + * + * The first methods are modeled after those in kernel_ipsec_t. + */ +struct ipsec_sa_mgr_t { + + /** + * Allocate an SPI for an inbound IPsec SA + * + * @param src source address of the SA + * @param dst destination address of the SA + * @param protocol protocol of the SA (only ESP supported) + * @param reqid reqid for the SA + * @param spi the allocated SPI + * @return SUCCESS of operation successful + */ + status_t (*get_spi)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int8_t protocol, u_int32_t reqid, u_int32_t *spi); + + /** + * Add a new SA + * + * @param src source address for this SA (gets cloned) + * @param dst destination address for this SA (gets cloned) + * @param spi SPI for this SA + * @param protocol protocol for this SA (only ESP is supported) + * @param reqid reqid for this SA + * @param mark mark for this SA (ignored) + * @param tfc Traffic Flow Confidentiality (not yet supported) + * @param lifetime lifetime for this SA + * @param enc_alg encryption algorithm for this SA + * @param enc_key encryption key for this SA + * @param int_alg integrity protection algorithm + * @param int_key integrity protection key + * @param mode mode for this SA (only tunnel mode is supported) + * @param ipcomp IPcomp transform (not supported, use IPCOMP_NONE) + * @param cpi CPI for IPcomp (ignored) + * @param encap enable UDP encapsulation (must be TRUE) + * @param esn Extended Sequence Numbers (currently not supported) + * @param inbound TRUE if this is an inbound SA, FALSE otherwise + * @param src_ts source traffic selector + * @param dst_ts destination traffic selector + * @return SUCCESS if operation completed + */ + status_t (*add_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int32_t reqid, + mark_t mark, u_int32_t tfc, lifetime_cfg_t *lifetime, + u_int16_t enc_alg, chunk_t enc_key, u_int16_t int_alg, + chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp, + u_int16_t cpi, bool encap, bool esn, bool inbound, + traffic_selector_t *src_ts, traffic_selector_t *dst_ts); + + /** + * Delete a previously added SA + * + * @param spi SPI of the SA + * @param src source address of the SA + * @param dst destination address of the SA + * @param protocol protocol of the SA + * @param cpi CPI for IPcomp + * @param mark optional mark + * @return SUCCESS if operation completed + */ + status_t (*del_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, u_int16_t cpi, + mark_t mark); + + /** + * Flush all SAs + * + * @return SUCCESS if operation completed + */ + status_t (*flush_sas)(ipsec_sa_mgr_t *this); + + /** + * Checkout an installed IPsec SA by SPI and destination address + * Can be used to find the correct SA for an inbound packet. + * + * The matching SA is locked until it is checked in using checkin(). + * If the matching SA is already checked out, this call blocks until the + * SA is checked in. + * + * Since other threads may be waiting for the checked out SA, it should be + * checked in as soon as possible after use. + * + * @param spi SPI (e.g. of an inbound packet) + * @param dst destination address (e.g. of an inbound packet) + * @return the matching IPsec SA, or NULL if none is found + */ + ipsec_sa_t *(*checkout_by_spi)(ipsec_sa_mgr_t *this, u_int32_t spi, + host_t *dst); + + /** + * Checkout an installed IPsec SA by its reqid and inbound/outbound flag. + * Can be used to find the correct SA for an outbound packet. + * + * The matching SA is locked until it is checked in using checkin(). + * If the matching SA is already checked out, this call blocks until the + * SA is checked in. + * + * Since other threads may be waiting for a checked out SA, it should be + * checked in as soon as possible after use. + * + * @param reqid reqid of the SA + * @param inbound TRUE for an inbound SA, FALSE for an outbound SA + * @return the matching IPsec SA, or NULL if none is found + */ + ipsec_sa_t *(*checkout_by_reqid)(ipsec_sa_mgr_t *this, u_int32_t reqid, + bool inbound); + + /** + * Checkin an SA after use. + * + * @param sa checked out SA + */ + void (*checkin)(ipsec_sa_mgr_t *this, ipsec_sa_t *sa); + + /** + * Destroy an ipsec_sa_mgr_t + */ + void (*destroy)(ipsec_sa_mgr_t *this); + +}; + +/** + * Create an ipsec_sa_mgr instance + * + * @return IPsec SA manager instance + */ +ipsec_sa_mgr_t *ipsec_sa_mgr_create(); + +#endif /** IPSEC_SA_MGR_H_ @}*/ diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index 3ff941794..8137493ab 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -9,6 +9,7 @@ libpts_la_SOURCES = \ libpts.h libpts.c \ pts/pts.h pts/pts.c \ pts/pts_error.h pts/pts_error.c \ + pts/pts_pcr.h pts/pts_pcr.c \ pts/pts_proto_caps.h \ pts/pts_req_func_comp_evid.h \ pts/pts_simple_evid_final.h \ diff --git a/src/libpts/Makefile.in b/src/libpts/Makefile.in index d317cfea1..0b6451bcc 100644 --- a/src/libpts/Makefile.in +++ b/src/libpts/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -77,8 +78,8 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(ipseclibdir)" LTLIBRARIES = $(ipseclib_LTLIBRARIES) libpts_la_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la -am_libpts_la_OBJECTS = libpts.lo pts.lo pts_error.lo pts_creds.lo \ - pts_database.lo pts_dh_group.lo pts_file_meas.lo \ +am_libpts_la_OBJECTS = libpts.lo pts.lo pts_error.lo pts_pcr.lo \ + pts_creds.lo pts_database.lo pts_dh_group.lo pts_file_meas.lo \ pts_file_meta.lo pts_file_type.lo pts_meas_algo.lo \ pts_component_manager.lo pts_comp_evidence.lo \ pts_comp_func_name.lo ita_comp_func_name.lo ita_comp_ima.lo \ @@ -96,7 +97,7 @@ am_libpts_la_OBJECTS = libpts.lo pts.lo pts_error.lo pts_creds.lo \ tcg_pts_attr_req_file_meas.lo tcg_pts_attr_file_meas.lo \ tcg_pts_attr_req_file_meta.lo tcg_pts_attr_unix_file_meta.lo libpts_la_OBJECTS = $(am_libpts_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -160,6 +161,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -254,11 +256,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -275,11 +280,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -295,6 +301,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -304,7 +311,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -339,6 +345,7 @@ libpts_la_SOURCES = \ libpts.h libpts.c \ pts/pts.h pts/pts.c \ pts/pts_error.h pts/pts_error.c \ + pts/pts_pcr.h pts/pts_pcr.c \ pts/pts_proto_caps.h \ pts/pts_req_func_comp_evid.h \ pts/pts_simple_evid_final.h \ @@ -469,6 +476,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pts_file_meta.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pts_file_type.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pts_meas_algo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pts_pcr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcg_attr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcg_comp_func_name.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcg_pts_attr_aik.Plo@am__quote@ @@ -524,6 +532,13 @@ pts_error.lo: pts/pts_error.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pts_error.lo `test -f 'pts/pts_error.c' || echo '$(srcdir)/'`pts/pts_error.c +pts_pcr.lo: pts/pts_pcr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pts_pcr.lo -MD -MP -MF $(DEPDIR)/pts_pcr.Tpo -c -o pts_pcr.lo `test -f 'pts/pts_pcr.c' || echo '$(srcdir)/'`pts/pts_pcr.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pts_pcr.Tpo $(DEPDIR)/pts_pcr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pts/pts_pcr.c' object='pts_pcr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pts_pcr.lo `test -f 'pts/pts_pcr.c' || echo '$(srcdir)/'`pts/pts_pcr.c + pts_creds.lo: pts/pts_creds.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pts_creds.lo -MD -MP -MF $(DEPDIR)/pts_creds.Tpo -c -o pts_creds.lo `test -f 'pts/pts_creds.c' || echo '$(srcdir)/'`pts/pts_creds.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pts_creds.Tpo $(DEPDIR)/pts_creds.Plo diff --git a/src/libpts/plugins/imc_attestation/Makefile.in b/src/libpts/plugins/imc_attestation/Makefile.in index 583d2dfee..4734379bf 100644 --- a/src/libpts/plugins/imc_attestation/Makefile.in +++ b/src/libpts/plugins/imc_attestation/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ imc_attestation_la_OBJECTS = $(am_imc_attestation_la_OBJECTS) imc_attestation_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(imc_attestation_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libpts/plugins/imc_attestation/imc_attestation.c b/src/libpts/plugins/imc_attestation/imc_attestation.c index 4f77ba093..7cb2a0671 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -108,9 +109,17 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, case TNC_CONNECTION_STATE_CREATE: state = imc_attestation_state_create(connection_id); return imc_attestation->create_state(imc_attestation, state); + case TNC_CONNECTION_STATE_HANDSHAKE: + if (imc_attestation->change_state(imc_attestation, connection_id, + new_state, &state) != TNC_RESULT_SUCCESS) + { + return TNC_RESULT_FATAL; + } + state->set_result(state, imc_id, + TNC_IMV_EVALUATION_RESULT_DONT_KNOW); + return TNC_RESULT_SUCCESS; case TNC_CONNECTION_STATE_DELETE: return imc_attestation->delete_state(imc_attestation, connection_id); - case TNC_CONNECTION_STATE_HANDSHAKE: case TNC_CONNECTION_STATE_ACCESS_ISOLATED: case TNC_CONNECTION_STATE_ACCESS_NONE: default: @@ -149,17 +158,15 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id, platform_info = pts->get_platform_info(pts); if (platform_info) { - pa_tnc_msg_t *pa_tnc_msg; + linked_list_t *attr_list; pa_tnc_attr_t *attr; - pa_tnc_msg = pa_tnc_msg_create(); + attr_list = linked_list_create(); attr = ietf_attr_product_info_create(0, 0, platform_info); - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - pa_tnc_msg->build(pa_tnc_msg); + attr_list->insert_last(attr_list, attr); result = imc_attestation->send_message(imc_attestation, connection_id, - FALSE, 0, TNC_IMVID_ANY, - pa_tnc_msg->get_encoding(pa_tnc_msg)); - pa_tnc_msg->destroy(pa_tnc_msg); + FALSE, 0, TNC_IMVID_ANY, attr_list); + attr_list->destroy(attr_list); } return result; @@ -176,11 +183,13 @@ static TNC_Result receive_message(TNC_IMCID imc_id, { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + pen_type_t type; linked_list_t *attr_list; imc_state_t *state; imc_attestation_state_t *attestation_state; enumerator_t *enumerator; TNC_Result result; + TNC_UInt32 target_imc_id; if (!imc_attestation) { @@ -204,6 +213,7 @@ static TNC_Result receive_message(TNC_IMCID imc_id, { return result; } + target_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? imc_id : dst_imc_id; /* preprocess any IETF standard error attributes */ result = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg) ? @@ -215,30 +225,40 @@ static TNC_Result receive_message(TNC_IMCID imc_id, enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF && - attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) - { - ietf_attr_pa_tnc_error_t *error_attr; - pen_t error_vendor_id; - pa_tnc_error_code_t error_code; - chunk_t msg_info; + type = attr->get_type(attr); - error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_vendor_id = error_attr->get_vendor_id(error_attr); - - if (error_vendor_id == PEN_TCG) + if (type.vendor_id == PEN_IETF) + { + if (type.type == IETF_ATTR_PA_TNC_ERROR) { + ietf_attr_pa_tnc_error_t *error_attr; + pen_type_t error_code; + chunk_t msg_info; + + error_attr = (ietf_attr_pa_tnc_error_t*)attr; error_code = error_attr->get_error_code(error_attr); - msg_info = error_attr->get_msg_info(error_attr); - DBG1(DBG_IMC, "received TCG-PTS error '%N'", - pts_error_code_names, error_code); - DBG1(DBG_IMC, "error information: %B", &msg_info); + if (error_code.vendor_id == PEN_TCG) + { + msg_info = error_attr->get_msg_info(error_attr); - result = TNC_RESULT_FATAL; + DBG1(DBG_IMC, "received TCG-PTS error '%N'", + pts_error_code_names, error_code.type); + DBG1(DBG_IMC, "error information: %B", &msg_info); + + result = TNC_RESULT_FATAL; + } + } + else if (type.type == IETF_ATTR_ASSESSMENT_RESULT) + { + ietf_attr_assess_result_t *ietf_attr; + + ietf_attr = (ietf_attr_assess_result_t*)attr; + state->set_result(state, target_imc_id, + ietf_attr->get_result(ietf_attr)); } } - else if (attr->get_vendor_id(attr) == PEN_TCG) + else if (type.vendor_id == PEN_TCG) { if (!imc_attestation_process(attr, attr_list, attestation_state, supported_algorithms, supported_dh_groups)) @@ -253,23 +273,11 @@ static TNC_Result receive_message(TNC_IMCID imc_id, if (result == TNC_RESULT_SUCCESS && attr_list->get_count(attr_list)) { - pa_tnc_msg = pa_tnc_msg_create(); - - enumerator = attr_list->create_enumerator(attr_list); - while (enumerator->enumerate(enumerator, &attr)) - { - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - } - enumerator->destroy(enumerator); - - pa_tnc_msg->build(pa_tnc_msg); result = imc_attestation->send_message(imc_attestation, connection_id, - FALSE, 0, TNC_IMVID_ANY, - pa_tnc_msg->get_encoding(pa_tnc_msg)); - pa_tnc_msg->destroy(pa_tnc_msg); + FALSE, 0, TNC_IMVID_ANY, attr_list); } - attr_list->destroy(attr_list); + return result; } diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_process.c b/src/libpts/plugins/imc_attestation/imc_attestation_process.c index b70c05370..bd2fa649d 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation_process.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation_process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ #include -#include #include #include @@ -57,10 +56,13 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, chunk_t attr_info; pts_t *pts; pts_error_code_t pts_error; + pen_type_t attr_type; bool valid_path; pts = attestation_state->get_pts(attestation_state); - switch (attr->get_type(attr)) + attr_type = attr->get_type(attr); + + switch (attr_type.type) { case TCG_PTS_REQ_PROTO_CAPS: { @@ -182,12 +184,12 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, case TCG_PTS_GET_TPM_VERSION_INFO: { chunk_t tpm_version_info, attr_info; + pen_type_t error_code = { PEN_TCG, TCG_PTS_TPM_VERS_NOT_SUPPORTED }; if (!pts->get_tpm_version_info(pts, &tpm_version_info)) { attr_info = attr->get_value(attr); - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_TPM_VERS_NOT_SUPPORTED, attr_info); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -221,6 +223,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, bool is_directory; u_int32_t delimiter; pts_file_meas_t *measurements; + pen_type_t error_code; attr_info = attr->get_value(attr); attr_cast = (tcg_pts_attr_req_file_meas_t*)attr; @@ -232,8 +235,8 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, if (valid_path && pts_error) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - pts_error, attr_info); + error_code = pen_type_create(PEN_TCG, pts_error); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -244,8 +247,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_INVALID_DELIMITER, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -254,8 +258,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, DBG2(DBG_IMC, "measurement request %d for %s '%s'", request_id, is_directory ? "directory" : "file", pathname); - measurements = pts->do_measurements(pts, request_id, - pathname, is_directory); + measurements = pts_file_meas_create_from_path(request_id, + pathname, is_directory, TRUE, + pts->get_meas_algorithm(pts)); if (!measurements) { /* TODO handle error codes from measurements */ @@ -273,6 +278,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, bool is_directory; u_int8_t delimiter; pts_file_meta_t *metadata; + pen_type_t error_code; attr_info = attr->get_value(attr); attr_cast = (tcg_pts_attr_req_file_meta_t*)attr; @@ -283,8 +289,8 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, valid_path = pts->is_path_valid(pts, pathname, &pts_error); if (valid_path && pts_error) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - pts_error, attr_info); + error_code = pen_type_create(PEN_TCG, pts_error); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -294,8 +300,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, } if (delimiter != SOLIDUS_UTF && delimiter != REVERSE_SOLIDUS_UTF) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_INVALID_DELIMITER, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_INVALID_DELIMITER); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -323,6 +330,7 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, pts_comp_func_name_t *name; pts_comp_evidence_t *evid; pts_component_t *comp; + pen_type_t error_code; u_int32_t depth; u_int8_t flags; status_t status; @@ -342,32 +350,36 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, if (flags & PTS_REQ_FUNC_COMP_EVID_TTC) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_UNABLE_DET_TTC, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_DET_TTC); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } if (flags & PTS_REQ_FUNC_COMP_EVID_VER && !(negotiated_caps & PTS_PROTO_CAPS_V)) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_UNABLE_LOCAL_VAL, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_LOCAL_VAL); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } if (flags & PTS_REQ_FUNC_COMP_EVID_CURR && !(negotiated_caps & PTS_PROTO_CAPS_C)) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_UNABLE_CUR_EVID, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_CUR_EVID); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } if (flags & PTS_REQ_FUNC_COMP_EVID_PCR && !(negotiated_caps & PTS_PROTO_CAPS_T)) { - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, - TCG_PTS_UNABLE_DET_PCR, attr_info); + error_code = pen_type_create(PEN_TCG, + TCG_PTS_UNABLE_DET_PCR); + attr = ietf_attr_pa_tnc_error_create(error_code, attr_info); attr_list->insert_last(attr_list, attr); break; } @@ -377,17 +389,19 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, "support sub component measurements"); return FALSE; } - comp = pts_components->create(pts_components, name, depth, NULL); + comp = attestation_state->create_component(attestation_state, + name, depth); if (!comp) { DBG2(DBG_IMC, " not registered: no evidence provided"); continue; } - /* do the component evidence measurement[s] */ + /* do the component evidence measurement[s] and cache them */ do { - status = comp->measure(comp, pts, &evid); + status = comp->measure(comp, name->get_qualifier(name), + pts, &evid); if (status == FAILED) { break; @@ -395,7 +409,6 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, attestation_state->add_evidence(attestation_state, evid); } while (status == NEED_MORE); - comp->destroy(comp); } e->destroy(e); break; @@ -408,12 +421,9 @@ bool imc_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, chunk_t pcr_composite, quote_sig; bool use_quote2; - /* Send buffered Simple Component Evidences */ + /* Send cached Component Evidence entries */ while (attestation_state->next_evidence(attestation_state, &evid)) { - pts->select_pcr(pts, evid->get_extended_pcr(evid)); - - /* Send Simple Component Evidence */ attr = tcg_pts_attr_simple_comp_evid_create(evid); attr_list->insert_last(attr_list, attr); } diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_state.c b/src/libpts/plugins/imc_attestation/imc_attestation_state.c index 72a55f60e..8ebabafa2 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation_state.c +++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,10 +15,15 @@ #include "imc_attestation_state.h" +#include + +#include + #include #include typedef struct private_imc_attestation_state_t private_imc_attestation_state_t; +typedef struct func_comp_t func_comp_t; /** * Private data of an imc_attestation_state_t object. @@ -40,6 +45,11 @@ struct private_imc_attestation_state_t { */ TNC_ConnectionState state; + /** + * Assessment/Evaluation Result + */ + TNC_IMV_Evaluation_Result result; + /** * Does the TNCCS connection support long message types? */ @@ -50,13 +60,23 @@ struct private_imc_attestation_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + /** * PTS object */ pts_t *pts; /** - * PTS Component Evidence list + * List of Functional Components + */ + linked_list_t *components; + + /** + * Functional Component Evidence cache list */ linked_list_t *list; @@ -87,18 +107,52 @@ METHOD(imc_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imc_state_t, set_max_msg_len, void, + private_imc_attestation_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imc_state_t, get_max_msg_len, u_int32_t, + private_imc_attestation_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imc_state_t, change_state, void, private_imc_attestation_state_t *this, TNC_ConnectionState new_state) { this->state = new_state; } +METHOD(imc_state_t, set_result, void, + private_imc_attestation_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result result) +{ + DBG1(DBG_IMC, "set assessment result for IMC %u to '%N'", + id, TNC_IMV_Evaluation_Result_names, result); + this->result = result; +} + +METHOD(imc_state_t, get_result, bool, + private_imc_attestation_state_t *this, TNC_IMCID id, + TNC_IMV_Evaluation_Result *result) +{ + if (result) + { + *result = this->result; + } + return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW; +} METHOD(imc_state_t, destroy, void, private_imc_attestation_state_t *this) { this->pts->destroy(this->pts); - this->list->destroy_offset(this->list, offsetof(pts_comp_evidence_t, destroy)); + this->components->destroy_offset(this->components, + offsetof(pts_component_t, destroy)); + this->list->destroy_offset(this->list, + offsetof(pts_comp_evidence_t, destroy)); free(this); } @@ -108,10 +162,42 @@ METHOD(imc_attestation_state_t, get_pts, pts_t*, return this->pts; } +METHOD(imc_attestation_state_t, create_component, pts_component_t*, + private_imc_attestation_state_t *this, pts_comp_func_name_t *name, + u_int32_t depth) +{ + enumerator_t *enumerator; + pts_component_t *component; + bool found = FALSE; + + enumerator = this->components->create_enumerator(this->components); + while (enumerator->enumerate(enumerator, &component)) + { + if (name->equals(name, component->get_comp_func_name(component))) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + + if (!found) + { + component = pts_components->create(pts_components, name, depth, NULL); + if (!component) + { + return NULL; + } + this->components->insert_last(this->components, component); + + } + return component; +} + METHOD(imc_attestation_state_t, add_evidence, void, - private_imc_attestation_state_t *this, pts_comp_evidence_t *evidence) + private_imc_attestation_state_t *this, pts_comp_evidence_t *evid) { - this->list->insert_last(this->list, evidence); + this->list->insert_last(this->list, evid); } METHOD(imc_attestation_state_t, next_evidence, bool, @@ -135,16 +221,23 @@ imc_state_t *imc_attestation_state_create(TNC_ConnectionID connection_id) .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, + .set_result = _set_result, + .get_result = _get_result, .destroy = _destroy, }, .get_pts = _get_pts, + .create_component = _create_component, .add_evidence = _add_evidence, .next_evidence = _next_evidence, }, .connection_id = connection_id, .state = TNC_CONNECTION_STATE_CREATE, + .result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW, .pts = pts_create(TRUE), + .components = linked_list_create(), .list = linked_list_create(), ); diff --git a/src/libpts/plugins/imc_attestation/imc_attestation_state.h b/src/libpts/plugins/imc_attestation/imc_attestation_state.h index 22b0bba23..e4fca71bb 100644 --- a/src/libpts/plugins/imc_attestation/imc_attestation_state.h +++ b/src/libpts/plugins/imc_attestation/imc_attestation_state.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -47,14 +48,24 @@ struct imc_attestation_state_t { pts_t* (*get_pts)(imc_attestation_state_t *this); /** - * Add an entry to the Component Evidence list + * Create and add an entry to the list of Functional Components * - * @param entry Component Evidence entry + * @param name Component Functional Name + * @param depth Sub-component Depth + * @return created functional component instance or NULL */ - void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *entry); + pts_component_t* (*create_component)(imc_attestation_state_t *this, + pts_comp_func_name_t *name, u_int32_t depth); /** - * Removes next Component Evidence entry from list and returns it + * Add an entry to the Component Evidence cache list + * + * @param evid Component Evidence entry + */ + void (*add_evidence)(imc_attestation_state_t *this, pts_comp_evidence_t *evid); + + /** + * Removes next entry from the Component Evidence cache list and returns it * * @param evid Next Component Evidence entry * @return TRUE if next entry is available diff --git a/src/libpts/plugins/imv_attestation/Makefile.am b/src/libpts/plugins/imv_attestation/Makefile.am index a550a3552..5e7465195 100644 --- a/src/libpts/plugins/imv_attestation/Makefile.am +++ b/src/libpts/plugins/imv_attestation/Makefile.am @@ -31,3 +31,5 @@ attest_LDADD = \ $(top_builddir)/src/libpts/libpts.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la attest.o : $(top_builddir)/config.status + +EXTRA_DIST = build-database.sh diff --git a/src/libpts/plugins/imv_attestation/Makefile.in b/src/libpts/plugins/imv_attestation/Makefile.in index 989a173b5..afb4abed7 100644 --- a/src/libpts/plugins/imv_attestation/Makefile.in +++ b/src/libpts/plugins/imv_attestation/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -94,7 +95,7 @@ attest_OBJECTS = $(am_attest_OBJECTS) attest_DEPENDENCIES = $(top_builddir)/src/libimcv/libimcv.la \ $(top_builddir)/src/libpts/libpts.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -120,6 +121,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -214,11 +216,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -235,11 +240,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -255,6 +261,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -264,7 +271,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -321,6 +327,7 @@ attest_LDADD = \ $(top_builddir)/src/libpts/libpts.la \ $(top_builddir)/src/libstrongswan/libstrongswan.la +EXTRA_DIST = build-database.sh all: all-am .SUFFIXES: diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c index 9200820e8..a202d128f 100644 --- a/src/libpts/plugins/imv_attestation/attest.c +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ /** * global debug output variables */ -static int debug_level = 2; +static int debug_level = 1; static bool stderr_quiet = TRUE; /** @@ -131,9 +131,14 @@ static void do_args(int argc, char *argv[]) { "directory", required_argument, NULL, 'D' }, { "dir", required_argument, NULL, 'D' }, { "file", required_argument, NULL, 'F' }, + { "sha1-ima", no_argument, NULL, 'I' }, { "key", required_argument, NULL, 'K' }, { "owner", required_argument, NULL, 'O' }, { "product", required_argument, NULL, 'P' }, + { "relative", no_argument, NULL, 'R' }, + { "rel", no_argument, NULL, 'R' }, + { "sequence", required_argument, NULL, 'S' }, + { "seq", required_argument, NULL, 'S' }, { "sha1", no_argument, NULL, '1' }, { "sha256", no_argument, NULL, '2' }, { "sha384", no_argument, NULL, '3' }, @@ -232,6 +237,9 @@ static void do_args(int argc, char *argv[]) exit(EXIT_FAILURE); } continue; + case 'I': + attest->set_algo(attest, PTS_MEAS_ALGO_SHA1_IMA); + continue; case 'K': { chunk_t aik; @@ -252,6 +260,12 @@ static void do_args(int argc, char *argv[]) exit(EXIT_FAILURE); } continue; + case 'R': + attest->set_relative(attest); + continue; + case 'S': + attest->set_sequence(attest, atoi(optarg)); + continue; case '1': attest->set_algo(attest, PTS_MEAS_ALGO_SHA1); continue; diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c index 88d19eee1..55afbf701 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.c +++ b/src/libpts/plugins/imv_attestation/attest_db.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,8 +16,14 @@ #include "attest_db.h" #include "libpts.h" +#include "pts/pts_meas_algo.h" +#include "pts/pts_file_meas.h" #include "pts/components/pts_comp_func_name.h" +#include + +#define IMA_MAX_NAME_LEN 255 + typedef struct private_attest_db_t private_attest_db_t; /** @@ -105,6 +111,16 @@ struct private_attest_db_t { */ bool product_set; + /** + * TRUE if relative filenames are to be used + */ + bool relative; + + /** + * Sequence number for ordering entries + */ + int seq_no; + /** * File measurement hash algorithm */ @@ -175,7 +191,7 @@ METHOD(attest_db_t, set_component, bool, e = this->db->query(this->db, "SELECT id FROM components " "WHERE vendor_id = ? AND name = ? AND qualifier = ?", - DB_INT, vid, DB_INT, name, DB_INT, qualifier, DB_INT); + DB_UINT, vid, DB_INT, name, DB_INT, qualifier, DB_INT); if (e) { if (e->enumerate(e, &this->cid)) @@ -231,7 +247,7 @@ METHOD(attest_db_t, set_cid, bool, e = this->db->query(this->db, "SELECT vendor_id, name, qualifier " "FROM components WHERE id = ?", - DB_INT, cid, DB_INT, DB_INT, DB_INT); + DB_UINT, cid, DB_INT, DB_INT, DB_INT); if (e) { if (e->enumerate(e, &vid, &name, &qualifier)) @@ -252,6 +268,7 @@ METHOD(attest_db_t, set_directory, bool, private_attest_db_t *this, char *dir, bool create) { enumerator_t *e; + size_t len; if (this->dir_set) { @@ -259,6 +276,13 @@ METHOD(attest_db_t, set_directory, bool, return FALSE; } free(this->dir); + + /* remove trailing '/' character */ + len = strlen(dir); + if (len && dir[len-1] == '/') + { + dir[len-1] = '\0'; + } this->dir = strdup(dir); e = this->db->query(this->db, @@ -308,7 +332,7 @@ METHOD(attest_db_t, set_did, bool, this->did = did; e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?", - DB_INT, did, DB_TEXT); + DB_UINT, did, DB_TEXT); if (e) { if (e->enumerate(e, &dir)) @@ -330,6 +354,7 @@ METHOD(attest_db_t, set_file, bool, private_attest_db_t *this, char *file, bool create) { enumerator_t *e; + char *filename; if (this->file_set) { @@ -337,9 +362,10 @@ METHOD(attest_db_t, set_file, bool, return FALSE; } this->file = strdup(file); + filename = this->relative ? basename(file) : file; e = this->db->query(this->db, "SELECT id FROM files WHERE path = ?", - DB_TEXT, file, DB_INT); + DB_TEXT, filename, DB_INT); if (e) { if (e->enumerate(e, &this->fid)) @@ -362,9 +388,9 @@ METHOD(attest_db_t, set_file, bool, /* Add a new database entry */ this->file_set = this->db->execute(this->db, &this->fid, "INSERT INTO files (type, path) VALUES (0, ?)", - DB_TEXT, file) == 1; + DB_TEXT, filename) == 1; - printf("file '%s' %sinserted into database\n", file, + printf("file '%s' %sinserted into database\n", filename, this->file_set ? "" : "could not be "); return this->file_set; @@ -384,7 +410,7 @@ METHOD(attest_db_t, set_fid, bool, this->fid = fid; e = this->db->query(this->db, "SELECT path FROM files WHERE id = ?", - DB_INT, fid, DB_TEXT); + DB_UINT, fid, DB_TEXT); if (e) { if (e->enumerate(e, &file)) @@ -468,7 +494,7 @@ METHOD(attest_db_t, set_kid, bool, this->kid = kid; e = this->db->query(this->db, "SELECT keyid, owner FROM keys WHERE id = ?", - DB_INT, kid, DB_BLOB, DB_TEXT); + DB_UINT, kid, DB_BLOB, DB_TEXT); if (e) { if (e->enumerate(e, &key, &owner)) @@ -545,7 +571,7 @@ METHOD(attest_db_t, set_pid, bool, this->pid = pid; e = this->db->query(this->db, "SELECT name FROM products WHERE id = ?", - DB_INT, pid, DB_TEXT); + DB_UINT, pid, DB_TEXT); if (e) { if (e->enumerate(e, &product)) @@ -568,6 +594,18 @@ METHOD(attest_db_t, set_algo, void, this->algo = algo; } +METHOD(attest_db_t, set_relative, void, + private_attest_db_t *this) +{ + this->relative = TRUE; +} + +METHOD(attest_db_t, set_sequence, void, + private_attest_db_t *this, int seq_no) +{ + this->seq_no = seq_no; +} + METHOD(attest_db_t, set_owner, void, private_attest_db_t *this, char *owner) { @@ -580,16 +618,29 @@ METHOD(attest_db_t, list_components, void, { enumerator_t *e; pts_comp_func_name_t *cfn; - int cid, vid, name, qualifier, count = 0; + int seq_no, cid, vid, name, qualifier, count = 0; if (this->kid) { e = this->db->query(this->db, - "SELECT c.id, c.vendor_id, c.name, c.qualifier " + "SELECT kc.seq_no, c.id, c.vendor_id, c.name, c.qualifier " "FROM components AS c " "JOIN key_component AS kc ON c.id = kc.component " - "WHERE kc.key = ? ORDER BY c.vendor_id, c.name, c.qualifier", - DB_INT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT); + "WHERE kc.key = ? ORDER BY kc.seq_no", + DB_UINT, this->kid, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT); + if (e) + { + while (e->enumerate(e, &cid, &seq_no, &vid, &name, &qualifier)) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%4d: #%-2d %s\n", seq_no, cid, print_cfn(cfn)); + cfn->destroy(cfn); + count++; + } + e->destroy(e); + printf("%d component%s found for key %#B\n", count, + (count == 1) ? "" : "s", &this->key); + } } else { @@ -597,24 +648,18 @@ METHOD(attest_db_t, list_components, void, "SELECT id, vendor_id, name, qualifier FROM components " "ORDER BY vendor_id, name, qualifier", DB_INT, DB_INT, DB_INT, DB_INT); - } - if (e) - { - while (e->enumerate(e, &cid, &vid, &name, &qualifier)) - { - cfn = pts_comp_func_name_create(vid, name, qualifier); - printf("%3d: %s\n", cid, print_cfn(cfn)); - cfn->destroy(cfn); - count++; - } - e->destroy(e); - - printf("%d component%s found", count, (count == 1) ? "" : "s"); - if (this->key_set) + if (e) { - printf(" for key %#B", &this->key); + while (e->enumerate(e, &cid, &vid, &name, &qualifier)) + { + cfn = pts_comp_func_name_create(vid, name, qualifier); + printf("%4d: %s\n", cid, print_cfn(cfn)); + cfn->destroy(cfn); + count++; + } + e->destroy(e); + printf("%d component%s found\n", count, (count == 1) ? "" : "s"); } - printf("\n"); } } @@ -632,12 +677,12 @@ METHOD(attest_db_t, list_keys, void, "SELECT k.id, k.keyid, k.owner FROM keys AS k " "JOIN key_component AS kc ON k.id = kc.key " "WHERE kc.component = ? ORDER BY k.keyid", - DB_INT, this->cid, DB_INT, DB_BLOB, DB_TEXT); + DB_UINT, this->cid, DB_INT, DB_BLOB, DB_TEXT); if (e) { while (e->enumerate(e, &kid, &keyid, &owner)) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); count++; } e->destroy(e); @@ -652,7 +697,7 @@ METHOD(attest_db_t, list_keys, void, { while (e->enumerate(e, &kid, &keyid, &owner)) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); count++; } e->destroy(e); @@ -681,13 +726,13 @@ METHOD(attest_db_t, list_files, void, "FROM files AS f " "JOIN product_file AS pf ON f.id = pf.file " "WHERE pf.product = ? ORDER BY f.path", - DB_INT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT); + DB_UINT, this->pid, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT); if (e) { while (e->enumerate(e, &fid, &type, &file, &meas, &meta)) { type = (type < 0 || type > 2) ? 0 : type; - printf("%3d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ", + printf("%4d: |%s%s| %s %s\n", fid, meas ? "M":" ", meta ? "T":" ", file_type[type], file); count++; } @@ -705,7 +750,7 @@ METHOD(attest_db_t, list_files, void, while (e->enumerate(e, &fid, &type, &file)) { type = (type < 0 || type > 2) ? 0 : type; - printf("%3d: %s %s\n", fid, file_type[type], file); + printf("%4d: %s %s\n", fid, file_type[type], file); count++; } e->destroy(e); @@ -734,12 +779,12 @@ METHOD(attest_db_t, list_products, void, "FROM products AS p " "JOIN product_file AS pf ON p.id = pf.product " "WHERE pf.file = ? ORDER BY p.name", - DB_INT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT); + DB_UINT, this->fid, DB_INT, DB_TEXT, DB_INT, DB_INT); if (e) { while (e->enumerate(e, &pid, &product, &meas, &meta)) { - printf("%3d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", + printf("%4d: |%s%s| %s\n", pid, meas ? "M":" ", meta ? "T":" ", product); count++; } @@ -755,7 +800,7 @@ METHOD(attest_db_t, list_products, void, { while (e->enumerate(e, &pid, &product)) { - printf("%3d: %s\n", pid, product); + printf("%4d: %s\n", pid, product); count++; } e->destroy(e); @@ -785,7 +830,7 @@ static void get_directory(private_attest_db_t *this, int did, char **directory) { e = this->db->query(this->db, "SELECT path from files WHERE id = ?", - DB_INT, did, DB_TEXT); + DB_UINT, did, DB_TEXT); if (e) { if (e->enumerate(e, &dir)) @@ -826,17 +871,17 @@ METHOD(attest_db_t, list_hashes, void, { if (this->fid != fid_old) { - printf("%3d: %s%s%s\n", this->fid, this->dir, + printf("%4d: %s%s%s\n", this->fid, this->dir, slash(this->dir, this->file) ? "/" : "", this->file); fid_old = this->fid; } - printf(" %#B\n", &hash); + printf(" %#B\n", &hash); count++; } e->destroy(e); printf("%d %N value%s found for product '%s'\n", count, - hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->product); } } @@ -848,7 +893,7 @@ METHOD(attest_db_t, list_hashes, void, "JOIN files AS f ON f.id = fh.file " "WHERE fh.algo = ? AND fh.product = ? " "ORDER BY fh.directory, f.path", - DB_INT, this->algo, DB_INT, this->pid, + DB_INT, this->algo, DB_UINT, this->pid, DB_INT, DB_TEXT, DB_BLOB, DB_INT); if (e) { @@ -860,18 +905,18 @@ METHOD(attest_db_t, list_hashes, void, { get_directory(this, did, &dir); } - printf("%3d: %s%s%s\n", fid, + printf("%4d: %s%s%s\n", fid, dir, slash(dir, file) ? "/" : "", file); fid_old = fid; did_old = did; } - printf(" %#B\n", &hash); + printf(" %#B\n", &hash); count++; } e->destroy(e); printf("%d %N value%s found for product '%s'\n", count, - hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->product); } } @@ -883,7 +928,7 @@ METHOD(attest_db_t, list_hashes, void, "JOIN products AS p ON p.id = fh.product " "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?" "ORDER BY p.name", - DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did, + DB_INT, this->algo, DB_UINT, this->fid, DB_UINT, this->did, DB_TEXT, DB_BLOB, DB_INT); if (e) { @@ -895,7 +940,7 @@ METHOD(attest_db_t, list_hashes, void, e->destroy(e); printf("%d %N value%s found for file '%s%s%s'\n", - count, hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + count, pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->dir, slash(this->dir, this->file) ? "/" : "", this->file); } @@ -922,17 +967,17 @@ METHOD(attest_db_t, list_hashes, void, get_directory(this, did, &dir); did_old = did; } - printf("%3d: %s%s%s\n", fid, + printf("%4d: %s%s%s\n", fid, dir, slash(dir, file) ? "/" : "", file); fid_old = fid; } - printf(" %#B '%s'\n", &hash, product); + printf(" %#B '%s'\n", &hash, product); count++; } e->destroy(e); - printf("%d %N value%s found\n", count, hash_algorithm_names, - pts_meas_algo_to_hash(this->algo), (count == 1) ? "" : "s"); + printf("%d %N value%s found\n", count, pts_meas_algorithm_names, + this->algo, (count == 1) ? "" : "s"); } } free(dir); @@ -956,7 +1001,7 @@ METHOD(attest_db_t, list_measurements, void, "JOIN keys AS k ON k.id = ch.key " "WHERE ch.algo = ? AND ch.key = ? AND ch.component = ? " "ORDER BY seq_no", - DB_INT, this->algo, DB_INT, this->kid, DB_INT, this->cid, + DB_INT, this->algo, DB_UINT, this->kid, DB_UINT, this->cid, DB_INT, DB_INT, DB_BLOB, DB_TEXT); if (e) { @@ -964,16 +1009,16 @@ METHOD(attest_db_t, list_measurements, void, { if (this->kid != kid_old) { - printf("%3d: %#B '%s'\n", this->kid, &this->key, owner); + printf("%4d: %#B '%s'\n", this->kid, &this->key, owner); kid_old = this->kid; } - printf("%5d %02d %#B\n", seq_no, pcr, &hash); + printf("%7d %02d %#B\n", seq_no, pcr, &hash); count++; } e->destroy(e); printf("%d %N value%s found for component '%s'\n", count, - hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", print_cfn(this->cfn)); } } @@ -985,7 +1030,7 @@ METHOD(attest_db_t, list_measurements, void, "JOIN keys AS k ON k.id = ch.key " "WHERE ch.algo = ? AND ch.component = ? " "ORDER BY keyid, seq_no", - DB_INT, this->algo, DB_INT, this->cid, + DB_INT, this->algo, DB_UINT, this->cid, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_BLOB, DB_TEXT); if (e) { @@ -993,16 +1038,16 @@ METHOD(attest_db_t, list_measurements, void, { if (kid != kid_old) { - printf("%3d: %#B '%s'\n", kid, &keyid, owner); + printf("%4d: %#B '%s'\n", kid, &keyid, owner); kid_old = kid; } - printf("%5d %02d %#B\n", seq_no, pcr, &hash); + printf("%7d %02d %#B\n", seq_no, pcr, &hash); count++; } e->destroy(e); printf("%d %N value%s found for component '%s'\n", count, - hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", print_cfn(this->cfn)); } @@ -1016,7 +1061,7 @@ METHOD(attest_db_t, list_measurements, void, "JOIN components AS c ON c.id = ch.component " "WHERE ch.algo = ? AND ch.key = ? " "ORDER BY vendor_id, name, qualifier, seq_no", - DB_INT, this->algo, DB_INT, this->kid, DB_INT, DB_INT, DB_BLOB, + DB_INT, this->algo, DB_UINT, this->kid, DB_INT, DB_INT, DB_BLOB, DB_INT, DB_INT, DB_INT, DB_INT); if (e) { @@ -1026,7 +1071,7 @@ METHOD(attest_db_t, list_measurements, void, if (cid != cid_old) { cfn = pts_comp_func_name_create(vid, name, qualifier); - printf("%3d: %s\n", cid, print_cfn(cfn)); + printf("%4d: %s\n", cid, print_cfn(cfn)); cfn->destroy(cfn); cid_old = cid; } @@ -1036,25 +1081,189 @@ METHOD(attest_db_t, list_measurements, void, e->destroy(e); printf("%d %N value%s found for key %#B '%s'\n", count, - hash_algorithm_names, pts_meas_algo_to_hash(this->algo), + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", &this->key, this->owner); } } } +bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, + chunk_t measurement, int fid, int did, bool ima, + int *hashes_added) +{ + enumerator_t *e; + chunk_t hash; + char *label; + + label = "could not be created"; + + e = this->db->query(this->db, + "SELECT hash FROM file_hashes WHERE algo = ? " + "AND file = ? AND directory = ? AND product = ? and key = 0", + DB_INT, algo, DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid, DB_BLOB); + if (!e) + { + printf("file_hashes query failed\n"); + return FALSE; + } + if (e->enumerate(e, &hash)) + { + label = chunk_equals(measurement, hash) ? + "exists and equals" : "exists and differs"; + } + else + { + if (this->db->execute(this->db, NULL, + "INSERT INTO file_hashes " + "(file, directory, product, key, algo, hash) " + "VALUES (?, ?, ?, 0, ?, ?)", + DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid, + DB_INT, algo, DB_BLOB, measurement) == 1) + { + label = "created"; + (*hashes_added)++; + } + } + e->destroy(e); + + printf(" %#B - %s%s\n", &measurement, ima ? "ima - " : "", label); + return TRUE; +} + METHOD(attest_db_t, add, bool, private_attest_db_t *this) { bool success = FALSE; + /* add key/component pair */ if (this->kid && this->cid) { success = this->db->execute(this->db, NULL, - "INSERT INTO key_component (key, component) VALUES (?, ?)", - DB_UINT, this->kid, DB_UINT, this->cid) == 1; + "INSERT INTO key_component (key, component, seq_no) " + "VALUES (?, ?, ?)", + DB_UINT, this->kid, DB_UINT, this->cid, + DB_UINT, this->seq_no) == 1; - printf("key/component pair (%d/%d) %sinserted into database\n", - this->kid, this->cid, success ? "" : "could not be "); + printf("key/component pair (%d/%d) %sinserted into database at " + "position %d\n", this->kid, this->cid, + success ? "" : "could not be ", this->seq_no); + + return success; + } + + /* add directory or file measurement for a given product */ + if ((this->did || this->fid) && this->pid) + { + char *pathname, *filename, *label; + char ima_buffer[IMA_MAX_NAME_LEN + 1]; + chunk_t measurement, ima_template; + pts_file_meas_t *measurements; + hasher_t *hasher = NULL; + bool ima = FALSE; + int fid, did; + int files_added = 0, hashes_added = 0, ima_hashes_added = 0; + enumerator_t *enumerator, *e; + + if (this->algo == PTS_MEAS_ALGO_SHA1_IMA) + { + ima = TRUE; + this->algo = PTS_MEAS_ALGO_SHA1; + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + printf("could not create hasher\n"); + return FALSE; + } + } + + pathname = this->did ? this->dir : this->file; + measurements = pts_file_meas_create_from_path(0, pathname, this->did, + this->relative, this->algo); + if (!measurements) + { + printf("file measurement failed\n"); + DESTROY_IF(hasher); + return FALSE; + } + if (this->fid && this->relative) + { + set_directory(this, dirname(pathname), TRUE); + } + did = this->relative ? this->did : 0; + + enumerator = measurements->create_enumerator(measurements); + while (enumerator->enumerate(enumerator, &filename, &measurement)) + { + /* retrieve or create filename */ + label = "could not be created"; + + e = this->db->query(this->db, + "SELECT id FROM files WHERE path = ?", + DB_TEXT, filename, DB_INT); + if (!e) + { + printf("files query failed\n"); + break; + } + if (e->enumerate(e, &fid)) + { + label = "exists"; + } + else + { + if (this->db->execute(this->db, &fid, + "INSERT INTO files (type, path) VALUES (0, ?)", + DB_TEXT, filename) == 1) + { + label = "created"; + files_added++; + } + } + e->destroy(e); + + printf("%4d: %s - %s\n", fid, filename, label); + + /* compute file measurement hash */ + if (!insert_file_hash(this, this->algo, measurement, + fid, did, FALSE, &hashes_added)) + { + break; + } + + if (!ima) + { + continue; + } + + /* compute IMA template hash */ + strncpy(ima_buffer, filename, IMA_MAX_NAME_LEN); + ima_buffer[IMA_MAX_NAME_LEN] = '\0'; + ima_template = chunk_create(ima_buffer, sizeof(ima_buffer)); + if (!hasher->get_hash(hasher, measurement, NULL) || + !hasher->get_hash(hasher, ima_template, measurement.ptr)) + { + printf("could not compute IMA template hash\n"); + break; + } + if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement, + fid, did, TRUE, &ima_hashes_added)) + { + break; + } + } + enumerator->destroy(enumerator); + + printf("%d measurements, added %d new files, %d new file hashes", + measurements->get_file_count(measurements), + files_added, hashes_added); + if (ima) + { + printf(" , %d new ima hashes", ima_hashes_added); + hasher->destroy(hasher); + } + printf("\n"); + measurements->destroy(measurements); + success = TRUE; } return success; } @@ -1064,12 +1273,42 @@ METHOD(attest_db_t, delete, bool, { bool success; + /* delete a file measurement hash for a given product */ + if (this->algo && this->pid && this->fid) + { + success = this->db->execute(this->db, NULL, + "DELETE FROM file_hashes " + "WHERE algo = ? AND product = ? " + "AND file = ? AND directory = ?", + DB_UINT, this->algo, DB_UINT, this->pid, + DB_UINT, this->fid, DB_UINT, this->did) > 0; + + printf("%4d: %s%s%s\n", this->fid, this->dir, this->did ? "/":"", + this->file); + printf("%N value for product '%s' %sdeleted from database\n", + pts_meas_algorithm_names, this->algo, this->product, + success ? "" : "could not be "); + + return success; + } + + /* delete product/file entries */ if (this->pid && (this->fid || this->did)) { - printf("deletion of product/file entries not supported yet\n"); - return FALSE; + success = this->db->execute(this->db, NULL, + "DELETE FROM product_file " + "WHERE product = ? AND file = ?", + DB_UINT, this->pid, + DB_UINT, this->fid ? this->fid : this->did) > 0; + + printf("product/file pair (%d/%d) %sdeleted from database\n", + this->pid, this->fid ? this->fid : this->did, + success ? "" : "could not be "); + + return success; } + /* delete key/component pair */ if (this->kid && this->cid) { success = this->db->execute(this->db, NULL, @@ -1173,6 +1412,8 @@ attest_db_t *attest_db_create(char *uri) .set_product = _set_product, .set_pid = _set_pid, .set_algo = _set_algo, + .set_relative = _set_relative, + .set_sequence = _set_sequence, .set_owner = _set_owner, .list_products = _list_products, .list_files = _list_files, @@ -1185,7 +1426,6 @@ attest_db_t *attest_db_create(char *uri) .destroy = _destroy, }, .dir = strdup(""), - .algo = PTS_MEAS_ALGO_SHA256, .db = lib->db->create(lib->db, uri), ); diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h index 9c9a9dcba..e32a368d8 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.h +++ b/src/libpts/plugins/imv_attestation/attest_db.h @@ -125,6 +125,21 @@ struct attest_db_t { */ void (*set_algo)(attest_db_t *this, pts_meas_algorithms_t algo); + /** + * Set that the IMA-specific SHA-1 template hash be computed + */ + void (*set_ima)(attest_db_t *this); + + /** + * Set that relative filenames are to be used + */ + void (*set_relative)(attest_db_t *this); + + /** + * Set the sequence number + */ + void (*set_sequence)(attest_db_t *this, int seq_no); + /** * Set owner [user/host] of an AIK * diff --git a/src/libpts/plugins/imv_attestation/attest_usage.c b/src/libpts/plugins/imv_attestation/attest_usage.c index e58f821e0..f7040f7ad 100644 --- a/src/libpts/plugins/imv_attestation/attest_usage.c +++ b/src/libpts/plugins/imv_attestation/attest_usage.c @@ -40,7 +40,7 @@ Usage:\n\ Show a list of measurement hashes for a given software product or\n\ its primary key as an optional selector.\n\ \n\ - ipsec attest --hashes [--sha1|--sha256|--sha384] [--file |--fid ]\n\ + ipsec attest --hashes [--sha1|--sha1-ima|--sha256|--sha384] [--file |--fid ]\n\ Show a list of measurement hashes for a given file or\n\ its primary key as an optional selector.\n\ \n\ @@ -52,11 +52,11 @@ Usage:\n\ Show a list of AIK key digests with a component or\n\ its primary key as an optional selector.\n\ \n\ - ipsec attest --measurements [--sha1|--sha256|--sha384] [--component |--cid ]\n\ + ipsec attest --measurements --sha1|--sha256|--sha384 [--component |--cid ]\n\ Show a list of component measurements for a given component or\n\ its primary key as an optional selector.\n\ \n\ - ipsec attest --measurements [--sha1|--sha256|--sha384] [--key |--kid |--aik ]\n\ + ipsec attest --measurements --sha1|--sha256|--sha384 [--key |--kid |--aik ]\n\ Show a list of component measurements for a given AIK or\n\ its primary key as an optional selector.\n\ \n\ @@ -67,14 +67,31 @@ Usage:\n\ ipsec attest --add [--owner ] --key |--aik \n\ Add an AIK public key digest entry preceded by an optional owner name\n\ \n\ + ipsec attest --add --product |--pid --sha1|--sha1-ima|--sha256|--sha384\n\ + [--relative|--rel] --dir |--file \n\ + Add hashes of a single file or all files in a directory under absolute or relative filenames\n\ + \n\ + ipsec attest --add --key --component |--cid --sequence |--seq \n\ + Add an ordered key/component entry\n\ + \n\ ipsec attest --del --file |--fid |--dir |--did \n\ Delete a file or directory entry referenced either by value or primary key\n\ \n\ ipsec attest --del --product |--pid |--component |--cid \n\ Delete a product or component entry referenced either by value or primary key\n\ \n\ + ipsec attest --del --product |--pid --file |--fid |--dir |--did \n\ + Delete a product/file entry referenced either by value or primary key\n\ + \n\ ipsec attest --del --key |--kid |--aik \n\ Delete an AIK entry referenced either by value or primary key\n\ + \n\ + ipsec attest --del --key --component |--cid \n\ + Delete a key/component entry\n\ + \n\ + ipsec attest --del --product |--pid --sha1|--sha1-ima|--sha256|--sha384\n\ + [--dir |--did ] --file |--fid \n\ + Delete a file hash given an absolute or relative filename\n\ \n"); } diff --git a/src/libpts/plugins/imv_attestation/build-database.sh b/src/libpts/plugins/imv_attestation/build-database.sh new file mode 100755 index 000000000..a89258e1d --- /dev/null +++ b/src/libpts/plugins/imv_attestation/build-database.sh @@ -0,0 +1,221 @@ +#!/bin/sh + +p="Ubuntu 12.04.1 LTS i686" + +ipsec attest --add --product "$p" --sha1-ima --dir /sbin +ipsec attest --add --product "$p" --sha1-ima --dir /usr/sbin +ipsec attest --add --product "$p" --sha1-ima --dir /bin +ipsec attest --add --product "$p" --sha1-ima --dir /usr/bin +ipsec attest --add --product "$p" --sha1-ima --dir /etc/acpi +ipsec attest --add --product "$p" --sha1-ima --file /etc/init.d/rc +ipsec attest --add --product "$p" --sha1-ima --file /etc/init.d/rcS +ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-post-down.d +ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-pre-up.d +ipsec attest --add --product "$p" --sha1-ima --dir /etc/network/if-up.d +ipsec attest --add --product "$p" --sha1-ima --file /etc/NetworkManager/dispatcher.d/01ifupdown +ipsec attest --add --product "$p" --sha1-ima --dir /etc/ppp/ip-down.d +ipsec attest --add --product "$p" --sha1-ima --dir /etc/rc2.d +ipsec attest --add --product "$p" --sha1-ima --dir /etc/rcS.d +ipsec attest --add --product "$p" --sha1-ima --file /etc/rc.local +ipsec attest --add --product "$p" --sha1-ima --dir /etc/resolvconf/update.d +ipsec attest --add --product "$p" --sha1-ima --file /etc/resolvconf/update-libc.d/avahi-daemon +ipsec attest --add --product "$p" --sha1-ima --dir /etc/update-motd.d +ipsec attest --add --product "$p" --sha1-ima --file /lib/crda/setregdomain +ipsec attest --add --product "$p" --sha1-ima --file /lib/init/apparmor-profile-load +ipsec attest --add --product "$p" --sha1-ima --file /lib/resolvconf/list-records +ipsec attest --add --product "$p" --sha1-ima --dir /lib/udev +ipsec attest --add --product "$p" --sha1-ima --file /lib/ufw/ufw-init +ipsec attest --add --product "$p" --sha1-ima --file /opt/Adobe/Reader9/Reader/intellinux/bin/acroread +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/accountsservice/accounts-daemon +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/apt/methods +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/at-spi2-core +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/avahi/avahi-daemon-check-dns.sh +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/bamf/bamfdaemon +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit/run-seat.d +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ConsoleKit/run-session.d +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/cups/notifier +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/dconf/dconf-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/dbus-1.0/dbus-daemon-launch-helper +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/deja-dup/deja-dup/deja-dup-monitor +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/evolution/3.2/evolution-alarm-notify +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/firefox/firefox +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/firefox/plugin-container +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gcc/i686-linux-gnu/4.6/cc1 +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gcc/i686-linux-gnu/4.6/collect2 +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/geoclue/geoclue-master +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/git-core +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-desktop3/check_gl_texture_size +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-disk-utility/gdu-notification-daemon +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-online-accounts/goa-daemon +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/gnome-settings-daemon +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-user-share/gnome-user-share +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gnome-screensaver/gnome-screensaver-dialog +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/gvfs +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/gvfs//gvfs-fuse-daemon +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/i386-linux-gnu/colord/colord +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/i386-linux-gnu/gconf +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-application/indicator-application-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-appmenu/hud-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-datetime/indicator-datetime-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-messages/indicator-messages-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-printers/indicator-printers-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-session/indicator-session-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/indicator-sound/indicator-sound-service +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/lightdm +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/NetworkManager/nm-dhcp-client.action +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/NetworkManager/nm-dispatcher.action +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/notify-osd/notify-osd +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/nux/unity_support_test +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/pm-utils/power.d +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/pm-utils/sleep.d +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/policykit-1/polkitd +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/pulseaudio/pulse/gconf-helper +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/rtkit/rtkit-daemon +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/system-service/system-service-d +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/telepathy/mission-control-5 +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/thunderbird/thunderbird +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ubuntuone-client +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/ubuntu-geoip/ubuntu-geoip-provider +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/ubuntu-sso-client +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/udisks +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity/unity-panel-service +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-applications/unity-applications-daemon +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-files/unity-files-daemon +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/unity-lens-music +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-lens-video/unity-lens-video +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/unity-scope-video-remote/unity-scope-video-remote +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/update-manager/release-upgrade-motd +ipsec attest --add --product "$p" --sha1-ima --dir /usr/lib/update-notifier +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/upower/upowerd +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/libvte-2.90-9/gnome-pty-helper +ipsec attest --add --product "$p" --sha1-ima --file /usr/lib/zeitgeist/zeitgeist-fts +ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport +ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport-checkreports +ipsec attest --add --product "$p" --sha1-ima --file /usr/share/apport/apport-gtk +ipsec attest --add --product "$p" --sha1-ima --dir /usr/share/language-tools +ipsec attest --add --product "$p" --sha1-ima --file /usr/share/virtualbox/VBoxCreateUSBNode.sh +ipsec attest --add --product "$p" --sha1-ima --relative --file /etc/ld.so.cache +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/i386-linux-gnu +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/i386-linux-gnu/security +for file in `find /lib/modules/3.2.21ima/kernel -name *.ko` +do +ipsec attest --add --product "$p" --sha1-ima --relative --file $file +done +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/plymouth +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/plymouth/renderers +ipsec attest --add --product "$p" --sha1-ima --relative --dir /lib/security +ipsec attest --add --product "$p" --sha1-ima --relative --dir /opt/Adobe/Reader9/Reader/intellinux/lib +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/apache2/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/compiz +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/compizconfig/backends/ +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/enchant +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libemiscwidgets.so.0.0.0 +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libeutil.so.0.0.0 +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/evolution/3.2/libgnomecanvas.so.0.0.0 +for file in /usr/lib/firefox/*.so +do +ipsec attest --add --product "$p" --sha1-ima --relative --file $file +done +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libbrowsercomps.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libdbusservice.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox/components/libmozgnome.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox-addons/extensions/globalmenu@ubuntu.com/components/libglobalmenu.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/firefox-addons/plugins/nppdf.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/flashplugin-installer/libflashplayer.so +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gedit/plugins +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gnome-bluetooth +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gnome-settings-daemon-3.0 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-2.0/2.10.0/menuproxies +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-3.0/3.0.0/menuproxies +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/gtk-3.0/3.0.0/theming-engines +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/alsa-lib +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/dri +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gconf/2 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gconv +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gio/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/2.10.0/engines +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-2.0/2.10.0/immodules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-3.0/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gtk-3.0/3.0.0/immodules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/gvfs +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/libcanberra-0.28 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/mesa +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/mit-krb5 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/openssl-1.0.0/engines +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/pango/1.6.0/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/pkcs11 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/polkit-1/extensions +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/nss +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/sane +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/i386-linux-gnu/sse2 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/indicators3/7 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/indicator-messages/status-providers/1 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/libpeas-1.0/loaders +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/man-db/libman-2.6.1.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/man-db/libmandb-2.6.1.so +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/mission-control-plugins.0 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/ModemManager +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/nautilus/extensions-3.0 +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/NetworkManager/libnm-settings-plugin-ifupdown.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/perl/5.14.2/auto/File/Glob/Glob.so +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/pulse-1.1/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/python2.7/lib-dynload +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/apt_inst.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/apt_pkg.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/cairo/_cairo.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/dbus/mainloop/qt.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/_dbus_bindings.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/_dbus_glib_bindings.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/duplicity/_librsync.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_gi.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_gobject/_gobject.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gi/_glib/_glib.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/glib/_glib.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gobject/_gobject.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/atk.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gtk/_gtk.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gio/_gio.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/gio/unix.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pango.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pangocairo.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/gtk-2.0/pynotify/_pynotify.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/crypto.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/rand.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/OpenSSL/SSL.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/PyQt4/QtCore.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/simplejson/_speedups.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/sip.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/twisted/internet/_sigchld.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/twisted/python/_initgroups.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/xapian/_xapian.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/python2.7/dist-packages/zope/interface/_zope_interface_coptimizations.so +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/rsyslog +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sane +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sse2 +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/sudo +for file in /usr/lib/thunderbird/*.so +do +ipsec attest --add --product "$p" --sha1-ima --relative --file $file +done +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird/components/libdbusservice.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird/components/libmozgnome.so +ipsec attest --add --product "$p" --sha1-ima --relative --file /usr/lib/thunderbird-addons/extensions/globalmenu@ubuntu.com/components/libglobalmenu.so +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/drivers +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/extensions +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/lib/xorg/modules/input +ipsec attest --add --product "$p" --sha1-ima --relative --dir /usr/share/fonts/truetype/ubuntu-font-family +ipsec attest --del --product "$p" --sha1 --file /lib/resolvconf/list-records +ipsec attest --del --product "$p" --sha1-ima --file /lib/resolvconf/list-records +ipsec attest --del --product "$p" --sha1 --file /usr/bin/lsb_release +ipsec attest --del --product "$p" --sha1-ima --file /usr/bin/lsb_release +ipsec attest --del --product "$p" --sha1 --file /usr/share/language-tools/language-options +ipsec attest --del --product "$p" --sha1-ima --file /usr/share/language-tools/language-options + diff --git a/src/libpts/plugins/imv_attestation/data.sql b/src/libpts/plugins/imv_attestation/data.sql index e6e03627a..b1646b724 100644 --- a/src/libpts/plugins/imv_attestation/data.sql +++ b/src/libpts/plugins/imv_attestation/data.sql @@ -42,6 +42,18 @@ INSERT INTO products ( 'Ubuntu 11.10 i686' ); +INSERT INTO products ( + name +) VALUES ( + 'Ubuntu 12.04 LTS i686' +); + +INSERT INTO products ( + name +) VALUES ( + 'Ubuntu 12.04.1 LTS i686' +); + /* Files */ INSERT INTO files ( /* 1 */ @@ -83,7 +95,7 @@ INSERT INTO files ( INSERT INTO files ( type, path ) VALUES ( - 1, '/lib/xtables/' + 1, '/lib/xtables' ); INSERT INTO files ( @@ -176,6 +188,19 @@ INSERT INTO files ( 0, '/etc/tnc_config' ); +INSERT INTO files ( + type, path +) VALUES ( + 0, '/lib/libxtables.so.7' +); + +INSERT INTO files ( + type, path +) VALUES ( + 0, '/sbin/xtables-multi' +); + + /* Product-File */ INSERT INTO product_file ( @@ -388,6 +413,48 @@ INSERT INTO product_file ( 7, 22, 1 ); +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 8, 1, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 8, 7, 1 +); + +INSERT INTO product_file ( + product, file, metadata +) VALUES ( + 8, 22, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 8, 23, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 8, 24, 1 +); + +INSERT INTO product_file ( + product, file, measurement +) VALUES ( + 9, 1, 1 +); + +INSERT INTO product_file ( + product, file, metadata +) VALUES ( + 9, 22, 1 +); + /* File Hashes */ INSERT INTO file_hashes ( @@ -426,6 +493,42 @@ INSERT INTO file_hashes ( 1, 7, 8192, X'301dad8829308f5a68c603a87bf961b91365f0346ac2f322de3ddcbb4645f56c0e6d2dc503ec2abff8fe8e895ce9304d' ); +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 8, 32768, X'9c3ed3179990c0ffb3a65b75a09b61faa4aca907' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 8, 16384, X'af474dd532c9f2d85c12368334eda3609a7c6287e08940f078547ab0f2871c94' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 8, 8192, X'a23fa7034dabdce2d10f2893d52b21d14fe24c6ae4c8570fb6c7190228046e4c064c4d29d736cd84ca42a3d9abf9bfde' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 9, 32768, X'9c3ed3179990c0ffb3a65b75a09b61faa4aca907' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 9, 16384, X'af474dd532c9f2d85c12368334eda3609a7c6287e08940f078547ab0f2871c94' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 1, 9, 8192, X'a23fa7034dabdce2d10f2893d52b21d14fe24c6ae4c8570fb6c7190228046e4c064c4d29d736cd84ca42a3d9abf9bfde' +); + INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( @@ -733,6 +836,24 @@ INSERT INTO file_hashes ( 8, 7, 7, 8192, X'63076ae505ce52c37878c9b6891ac516320046403aec25bf347c7011c2d28d5db7e2946d1fae3006ab4ef43716ff4558' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 8, 7, 8, 32768, X'a93f870078b69ba530e6335eaee698908b12078f' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 8, 7, 8, 16384, X'0c31c1f41a57f4b15fafeb541de475e6da88380c911bb606b35413fda8428006' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 8, 7, 8, 8192, X'bb8fc7073691910d315621de176be64316923782df8d836b384414fd9a3d293be5bea51811ee6ef68a497f12384bba42' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -805,6 +926,24 @@ INSERT INTO file_hashes ( 9, 7, 7, 8192, X'5d3637413b9e318d0e0be6a9da86121062b99d1bdb084dfda4222baa71b250de644b4024281760b4eae926e03fac4fdb' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 9, 7, 8, 32768, X'225836cb243c3502d90c92c3eb54310403303270' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 9, 7, 8, 16384, X'7862ed16eeb35d2f10e6d416a6fcbe8000ba1bbc2daddd15f43b375686308d7d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 9, 7, 8, 8192, X'd4b6b939d0fdcd84bbc66fbf9bd044a61de823b4acb52e0ead7ae7f955d9b2d6399da1f673eadbb4792b819923e5e845' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -859,6 +998,24 @@ INSERT INTO file_hashes ( 10, 7, 7, 8192, X'858310a6e4b6311c491c4370990bfd6b9f03a49bb5ddf45b0d788f7043f130016e11be6bd95db66e49e2906a87adf8cb' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 10, 7, 8, 32768, X'008374e704c81351c333a214f4ee2d89e996f344' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 10, 7, 8, 16384, X'0e28034f99a3e0cdffa64bf126858afb48ee25b5cbfc70bbcd997bab7ef1e056' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 10, 7, 8, 8192, X'b6e01ba0706e48ce37abef3fbc59a45fd50c7abd3bb7950b1d892bc4a0db3f9784f573d74ef51376267183d26513d1d0' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -913,6 +1070,24 @@ INSERT INTO file_hashes ( 11, 7, 7, 8192, X'a2d33fa2d0ee7bffa5e628f88ccb83cd61bb4c5fe6d2edb8b853b83d8c43f498fa6e8da70510f0a1a3ddb36060bbd4d8' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 11, 7, 8, 32768, X'105fc70c5ecde30ebe841ac0a229b77b6d5f3d8a' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 11, 7, 8, 16384, X'e4cdc17b835eabe06d719bccada0e59d3ee5eb3759ca75eb9c037166e8dafd30' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 11, 7, 8, 8192, X'a9f6a18ff6f85208583e0b3fdd2fdafc4575baf5d973c7a831ce74d8bb5a24b8ae8e4504ddefa4a2c2b91f31cd68edea' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -949,6 +1124,24 @@ INSERT INTO file_hashes ( 12, 7, 7, 8192, X'1a4a6d91bda3ce59e6c444ccc1e758c9c6f0e223fd8c5aac369260cdfa83081c0e8f3753f100490910ec161902f10ba7' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 12, 7, 8, 32768, X'a9d8ea0203810d269b3ef3d974fed2ac4d486bae' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 12, 7, 8, 16384, X'c071aedaa6f66f8ab45ce037d72bbc42fb1894ac69ab689ad21ce6ff0c1c5d6a' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 12, 7, 8, 8192, X'1612eb51a3be3fcba24808326e29967b6f798c5140aefc8279601c5f5600030148fd01e8fbe737fba9c3972832e67601' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -985,6 +1178,24 @@ INSERT INTO file_hashes ( 13, 7, 7, 8192, X'014852b73cd3eabfa955b7bd56b269d5a0590a2770cf3d656b3d68dbad30884327fc81ff96c6f661c9c4189c3aefa346' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 13, 7, 8, 32768, X'da655441bf10f7dc32978474c77903f2f9120cc4' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 13, 7, 8, 16384, X'ec6a4bb332af51cf60cc30ce95197a8c89d42e6135d6e0d4e1d9e4bcc88e838c' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 13, 7, 8, 8192, X'135a84e988f219d5bcd7cb4e7ada6f9239c0164a0021262be0c4f9c00d8bece341aa88e0e35011b195c737e438225f4b' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -1021,6 +1232,24 @@ INSERT INTO file_hashes ( 14, 7, 7, 8192, X'f701cb25b0e9a9f32d3bba9b274ca0e8838363d13b7283b842d6c9673442890e538127c3b64ca4b177de1d243b44cf0d' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 14, 7, 8, 32768, X'7b401b741cc32bcc86c3eac43059c9dd26e99a40' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 14, 7, 8, 16384, X'9a7cf37befecc40b494f9176bb887dd478e72c750fed8d540e5d7bbf4b5f2765' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 14, 7, 8, 8192, X'161c2f502f10a72ef159b6308219c38cb13387e21645e4357e6934d7afc62727cd76fd518dc6f676e2db47125eb9a2f6' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -1057,6 +1286,24 @@ INSERT INTO file_hashes ( 15, 7, 7, 8192, X'8038830a994c779bc200e844d8768280feca9dd5d58de6cd359b87cc68846799edfd16e36e83002da4bb309cfd3b353d' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 15, 7, 8, 32768, X'129f6ecfb596fd751e33209b2ad2a28f2d243fdc' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 15, 7, 8, 16384, X'2fd1e8874b2faf18973881af54bd3e1fd21aaa8ee181313919569715885e69bc' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 15, 7, 8, 8192, X'3862f52ec823474ccfffeb6ead7c6a18b132057018704cb2fa05b08aaee3a1abfaf0eb4c826348f427dfbbb5b3e56647' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -1093,6 +1340,24 @@ INSERT INTO file_hashes ( 16, 7, 7, 8192, X'4be6e7978a6e4fb8a792815f2bbe28c2e66276401fb98ca90e49a5c2f2c94a1c7aac635d501d35d1db0fd53a0cb9d0fa' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 8, 32768, X'2b686cd8359dea842cfdcacf39d22f5e0e6d06f2' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 8, 16384, X'e14fb3f87b9539108e023660f2d7b4fc728b0622a85de89bdc1fe20162f200a3' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 16, 7, 8, 8192, X'6f55292ad4061b0575dca0a3e6abe5f86d5288e0b860e6f76715bd5c9df8b5f751bc547d3147e9da12593b56a3f83252' +); + INSERT INTO file_hashes ( file, product, algo, hash ) VALUES ( @@ -1183,6 +1448,24 @@ INSERT INTO file_hashes ( 18, 7, 7, 8192, X'4da3955f1fd968ecf95cff825d42715b544e577f28f411a020a270834235125bc0c8872bac8dd3466349ac8ab0aa2d74' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 18, 7, 8, 32768, X'9ff04217b3b40cb328440e40b6dc1c283f9f71ec' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 18, 7, 8, 16384, X'76de3b5b8df6d685e522aeea01d79ac457808437c02d40eb2e6ff06098057d41' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 18, 7, 8, 8192, X'ca1c0f6e3516f82a40cbaaea84dd42a8c97cea6b729dc07343f18a5d1b898a94e861b0dfb574c3efad64c363bb07ebf5' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -1219,6 +1502,24 @@ INSERT INTO file_hashes ( 19, 7, 7, 8192, X'7b5b16840da590a995fab23533f41982c5b136bff8e9b9a90b3c919a12cee20d312091455057a8bba9d9fbe314e6203d' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 19, 7, 8, 32768, X'b3d6df204cc27f59704c19ab501172892a9c7c5d' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 19, 7, 8, 16384, X'9168ba26a67a3daf0ad3ea956d88358235ebb968b95f91bd110eab34ba75e4f8' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 19, 7, 8, 8192, X'e3a69702f9d07ea6e1f7cb85157f3d76d7e7dc577fd48ca7f6cf8f917ca7e5015e0f7dd463e1229aebf18aabcfd39cc3' +); + INSERT INTO file_hashes ( file, directory, product, algo, hash ) VALUES ( @@ -1255,6 +1556,60 @@ INSERT INTO file_hashes ( 20, 7, 7, 8192, X'84200bd318bb022915150842ddf4002e061ef593604ad0d07021dc662cc40bfa749cce084ddf25d0e5137f6380f613d8' ); +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 8, 32768, X'8696176c12bf8291b6b9989ec5c94c3fdf26b14f' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 8, 16384, X'e7b5896d1dbe17f501f20424e8ed7d2de14d79e984e0c0a032ea70ca2f44e83a' +); + +INSERT INTO file_hashes ( + file, directory, product, algo, hash +) VALUES ( + 20, 7, 8, 8192, X'0d87fb31cf84b57b5b872af0b5e65610df929e48877f5ea199c073da6087c7a0e4b4c186545f654bb5db94284fde6274' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 23, 8, 32768, X'a67433717c2b9e2a9293f15a88456efbf7998a84' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 23, 8, 16384, X'1453d3ceaea4043cecd34f1eb24e0fbbe9fe04978077d06a0f728de849e71365' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 23, 8, 8192, X'abd1134f68a2daf92183aeae372f970cb076164468d4df08b8cb53743cae0867c17231e8f087e3367b6ec6905eb03c16' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 24, 8, 32768, X'bc3f9d1edeb00192c5c040a53823b58642ed8f41' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 24, 8, 16384, X'78f76b5c274705d09cd73cfad04791b8009c56d00849a00613909a659dc9ac63' +); + +INSERT INTO file_hashes ( + file, product, algo, hash +) VALUES ( + 24, 8, 8192, X'52cea5a859d0a1e06ffa8c1fc4f7b8dffde2de99915d660b2d3756315efdd873bee67ba3732f2c1ec692c38a8780cd72' +); + /* AIKs */ INSERT INTO keys ( @@ -1280,7 +1635,13 @@ INSERT INTO components ( INSERT INTO components ( vendor_id, name, qualifier ) VALUES ( - 36906, 3, 33 /* ITA IMA */ + 36906, 3, 33 /* ITA IMA - Trusted Platform */ +); + +INSERT INTO components ( + vendor_id, name, qualifier +) VALUES ( + 36906, 3, 34 /* ITA IMA - Operating System */ ); /* AIK Component */ @@ -1288,18 +1649,18 @@ INSERT INTO components ( INSERT INTO key_component ( key, component, depth, seq_no ) VALUES ( - 2, 2, 0, 1 + 1, 3, 0, 1 ); INSERT INTO key_component ( key, component, depth, seq_no ) VALUES ( - 1, 3, 0, 1 + 1, 2, 0, 2 ); INSERT INTO key_component ( key, component, depth, seq_no ) VALUES ( - 1, 2, 0, 2 + 1, 4, 0, 3 ); diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c index 51069b02d..201496e8a 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -168,13 +168,10 @@ TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id, static TNC_Result send_message(TNC_ConnectionID connection_id) { - pa_tnc_msg_t *msg; - pa_tnc_attr_t *attr; + linked_list_t *attr_list; imv_state_t *state; imv_attestation_state_t *attestation_state; TNC_Result result; - linked_list_t *attr_list; - enumerator_t *enumerator; if (!imv_attestation->get_state(imv_attestation, connection_id, &state)) { @@ -188,21 +185,8 @@ static TNC_Result send_message(TNC_ConnectionID connection_id) { if (attr_list->get_count(attr_list)) { - msg = pa_tnc_msg_create(); - - /* move PA-TNC attributes to PA-TNC message */ - enumerator = attr_list->create_enumerator(attr_list); - while (enumerator->enumerate(enumerator, &attr)) - { - msg->add_attribute(msg, attr); - } - enumerator->destroy(enumerator); - - msg->build(msg); result = imv_attestation->send_message(imv_attestation, - connection_id, FALSE, 0, TNC_IMCID_ANY, - msg->get_encoding(msg)); - msg->destroy(msg); + connection_id, FALSE, 0, TNC_IMCID_ANY, attr_list); } else { @@ -230,6 +214,7 @@ static TNC_Result receive_message(TNC_IMVID imv_id, { pa_tnc_msg_t *pa_tnc_msg; pa_tnc_attr_t *attr; + pen_type_t type; linked_list_t *attr_list; imv_state_t *state; imv_attestation_state_t *attestation_state; @@ -271,31 +256,31 @@ static TNC_Result receive_message(TNC_IMVID imv_id, enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg); while (enumerator->enumerate(enumerator, &attr)) { - if (attr->get_vendor_id(attr) == PEN_IETF) + type = attr->get_type(attr); + + if (type.vendor_id == PEN_IETF) { - if (attr->get_type(attr) == IETF_ATTR_PA_TNC_ERROR) + if (type.type == IETF_ATTR_PA_TNC_ERROR) { ietf_attr_pa_tnc_error_t *error_attr; - pen_t error_vendor_id; - pa_tnc_error_code_t error_code; + pen_type_t error_code; chunk_t msg_info; error_attr = (ietf_attr_pa_tnc_error_t*)attr; - error_vendor_id = error_attr->get_vendor_id(error_attr); + error_code = error_attr->get_error_code(error_attr); - if (error_vendor_id == PEN_TCG) + if (error_code.vendor_id == PEN_TCG) { - error_code = error_attr->get_error_code(error_attr); msg_info = error_attr->get_msg_info(error_attr); DBG1(DBG_IMV, "received TCG-PTS error '%N'", - pts_error_code_names, error_code); + pts_error_code_names, error_code.type); DBG1(DBG_IMV, "error information: %B", &msg_info); result = TNC_RESULT_FATAL; } } - else if (attr->get_type(attr) == IETF_ATTR_PRODUCT_INFORMATION) + else if (type.type == IETF_ATTR_PRODUCT_INFORMATION) { ietf_attr_product_info_t *attr_cast; char *platform_info; @@ -305,7 +290,7 @@ static TNC_Result receive_message(TNC_IMVID imv_id, pts->set_platform_info(pts, platform_info); } } - else if (attr->get_vendor_id(attr) == PEN_TCG) + else if (type.vendor_id == PEN_TCG) { if (!imv_attestation_process(attr, attr_list, attestation_state, supported_algorithms,supported_dh_groups, pts_db, pts_credmgr)) @@ -325,29 +310,14 @@ static TNC_Result receive_message(TNC_IMVID imv_id, TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, TNC_IMV_EVALUATION_RESULT_ERROR); return imv_attestation->provide_recommendation(imv_attestation, - connection_id); + connection_id, src_imc_id); } if (attr_list->get_count(attr_list)) { - pa_tnc_msg = pa_tnc_msg_create(); - - /* move PA-TNC attributes to PA-TNC message */ - enumerator = attr_list->create_enumerator(attr_list); - while (enumerator->enumerate(enumerator, &attr)) - { - pa_tnc_msg->add_attribute(pa_tnc_msg, attr); - } - enumerator->destroy(enumerator); - - pa_tnc_msg->build(pa_tnc_msg); result = imv_attestation->send_message(imv_attestation, connection_id, - FALSE, 0, TNC_IMCID_ANY, - pa_tnc_msg->get_encoding(pa_tnc_msg)); - - pa_tnc_msg->destroy(pa_tnc_msg); + FALSE, 0, TNC_IMCID_ANY, attr_list); attr_list->destroy(attr_list); - return result; } attr_list->destroy(attr_list); @@ -360,7 +330,7 @@ static TNC_Result receive_message(TNC_IMVID imv_id, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION, TNC_IMV_EVALUATION_RESULT_ERROR); return imv_attestation->provide_recommendation(imv_attestation, - connection_id); + connection_id, src_imc_id); } if (attestation_state->get_handshake_state(attestation_state) == @@ -372,12 +342,6 @@ static TNC_Result receive_message(TNC_IMVID imv_id, attestation_state->get_file_meas_request_count(attestation_state)); attestation_state->set_measurement_error(attestation_state); } - if (attestation_state->get_component_count(attestation_state)) - { - DBG1(DBG_IMV, "failure due to %d components waiting for evidence", - attestation_state->get_component_count(attestation_state)); - attestation_state->set_measurement_error(attestation_state); - } if (attestation_state->get_measurement_error(attestation_state)) { state->set_recommendation(state, @@ -391,7 +355,7 @@ static TNC_Result receive_message(TNC_IMVID imv_id, TNC_IMV_EVALUATION_RESULT_COMPLIANT); } return imv_attestation->provide_recommendation(imv_attestation, - connection_id); + connection_id, src_imc_id); } return result; @@ -446,7 +410,7 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id, return TNC_RESULT_NOT_INITIALIZED; } return imv_attestation->provide_recommendation(imv_attestation, - connection_id); + connection_id, TNC_IMCID_ANY); } /** diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_build.c b/src/libpts/plugins/imv_attestation/imv_attestation_build.c index 4f2cc1e95..23195d6e3 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_build.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_build.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -16,7 +16,6 @@ #include "imv_attestation_build.h" #include "imv_attestation_state.h" -#include #include #include #include @@ -198,7 +197,13 @@ bool imv_attestation_build(linked_list_t *attr_list, attr_list->insert_last(attr_list, attr); } enumerator->destroy(enumerator); - break; + + /* do we have any file metadata or measurement requests? */ + if (attr_list->get_count(attr_list)) + { + break; + } + /* fall through to next state */ } case IMV_ATTESTATION_STATE_COMP_EVID: { @@ -252,15 +257,15 @@ bool imv_attestation_build(linked_list_t *attr_list, comp_name = pts_comp_func_name_create(vid, name, qualifier); comp_name->log(comp_name, " "); - comp = pts_components->create(pts_components, comp_name, - depth, pts_db); + comp = attestation_state->create_component(attestation_state, + comp_name, depth, pts_db); if (!comp) { - DBG2(DBG_IMV, " not registered: removed from request"); + DBG2(DBG_IMV, " not registered or duplicate" + " - removed from request"); comp_name->destroy(comp_name); continue; } - attestation_state->add_component(attestation_state, comp); if (first_component) { attr = tcg_pts_attr_req_func_comp_evid_create(); @@ -290,8 +295,11 @@ bool imv_attestation_build(linked_list_t *attr_list, break; } case IMV_ATTESTATION_STATE_EVID_FINAL: - attestation_state->set_handshake_state(attestation_state, + if (attestation_state->components_finalized(attestation_state)) + { + attestation_state->set_handshake_state(attestation_state, IMV_ATTESTATION_STATE_END); + } break; case IMV_ATTESTATION_STATE_END: break; diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_process.c b/src/libpts/plugins/imv_attestation/imv_attestation_process.c index a742b6697..37e9ac77a 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_process.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_process.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -41,11 +41,13 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, pts_database_t *pts_db, credential_manager_t *pts_credmgr) { + pen_type_t attr_type; pts_t *pts; - + pts = attestation_state->get_pts(attestation_state); - - switch (attr->get_type(attr)) + attr_type = attr->get_type(attr); + + switch (attr_type.type) { case TCG_PTS_PROTO_CAPS: { @@ -169,7 +171,7 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, KEY_ANY, aik->get_issuer(aik), FALSE); while (e->enumerate(e, &issuer)) { - if (aik->issued_by(aik, issuer)) + if (aik->issued_by(aik, issuer, NULL)) { trusted = TRUE; break; @@ -216,22 +218,29 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, DBG1(DBG_IMV, "measurement request %d returned %d file%s:", request_id, file_count, (file_count == 1) ? "":"s"); - if (!attestation_state->check_off_file_meas_request(attestation_state, - request_id, &file_id, &is_dir)) + if (request_id) { - DBG1(DBG_IMV, " no entry found for file measurement request %d", - request_id); - break; - } + if (!attestation_state->check_off_file_meas_request( + attestation_state, request_id, &file_id, &is_dir)) + { + DBG1(DBG_IMV, " no entry found for file measurement " + "request %d", request_id); + break; + } - /* check hashes from database against measurements */ - e_hash = pts_db->create_file_hash_enumerator(pts_db, - platform_info, algo, file_id, is_dir); - if (!measurements->verify(measurements, e_hash, is_dir)) + /* check hashes from database against measurements */ + e_hash = pts_db->create_file_hash_enumerator(pts_db, + platform_info, algo, file_id, is_dir); + if (!measurements->verify(measurements, e_hash, is_dir)) + { + attestation_state->set_measurement_error(attestation_state); + } + e_hash->destroy(e_hash); + } + else { - attestation_state->set_measurement_error(attestation_state); + measurements->check(measurements, pts_db, platform_info, algo); } - e_hash->destroy(e_hash); break; } case TCG_PTS_UNIX_FILE_META: @@ -276,34 +285,22 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, pts_comp_evidence_t *evidence; pts_component_t *comp; u_int32_t depth; - status_t status; attr_cast = (tcg_pts_attr_simple_comp_evid_t*)attr; evidence = attr_cast->get_comp_evidence(attr_cast); name = evidence->get_comp_func_name(evidence, &depth); - comp = attestation_state->check_off_component(attestation_state, name); + comp = attestation_state->get_component(attestation_state, name); if (!comp) { DBG1(DBG_IMV, " no entry found for component evidence request"); break; } - status = comp->verify(comp, pts, evidence); - - switch (status) + if (comp->verify(comp, name->get_qualifier(name), pts, + evidence) != SUCCESS) { - default: - case FAILED: - attestation_state->set_measurement_error(attestation_state); - comp->destroy(comp); - break; - case SUCCESS: - name->log(name, " successfully measured "); - comp->destroy(comp); - break; - case NEED_MORE: - /* re-enter component into list */ - attestation_state->add_component(attestation_state, comp); + attestation_state->set_measurement_error(attestation_state); + name->log(name, " measurement mismatch for "); } break; } @@ -353,8 +350,11 @@ bool imv_attestation_process(pa_tnc_attr_t *attr, linked_list_t *attr_list, DBG2(DBG_IMV, "TPM Quote Info signature verification successful"); free(quote_info.ptr); - /* Finalize any pending measurement registrations */ - attestation_state->check_off_registrations(attestation_state); + /** + * Finalize any pending measurement registrations and check + * if all expected component measurements were received + */ + attestation_state->finalize_components(attestation_state); } if (attr_cast->get_evid_sig(attr_cast, &evid_sig)) diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c index a58fd3ec3..1dbc88309 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,21 +15,15 @@ #include "imv_attestation_state.h" +#include + #include #include #include typedef struct private_imv_attestation_state_t private_imv_attestation_state_t; typedef struct file_meas_request_t file_meas_request_t; - -/** - * PTS File/Directory Measurement request entry - */ -struct file_meas_request_t { - u_int16_t id; - int file_id; - bool is_dir; -}; +typedef struct func_comp_t func_comp_t; /** * Private data of an imv_attestation_state_t object. @@ -61,6 +55,11 @@ struct private_imv_attestation_state_t { */ bool has_excl; + /** + * Maximum PA-TNC message size for this TNCCS connection + */ + u_int32_t max_msg_len; + /** * IMV Attestation handshake state */ @@ -103,6 +102,32 @@ struct private_imv_attestation_state_t { }; +/** + * PTS File/Directory Measurement request entry + */ +struct file_meas_request_t { + u_int16_t id; + int file_id; + bool is_dir; +}; + +/** + * PTS Functional Component entry + */ +struct func_comp_t { + pts_component_t *comp; + u_int8_t qualifier; +}; + +/** + * Frees a func_comp_t object + */ +static void free_func_comp(func_comp_t *this) +{ + this->comp->destroy(this->comp); + free(this); +} + typedef struct entry_t entry_t; /** @@ -150,6 +175,18 @@ METHOD(imv_state_t, set_flags, void, this->has_excl = has_excl; } +METHOD(imv_state_t, set_max_msg_len, void, + private_imv_attestation_state_t *this, u_int32_t max_msg_len) +{ + this->max_msg_len = max_msg_len; +} + +METHOD(imv_state_t, get_max_msg_len, u_int32_t, + private_imv_attestation_state_t *this) +{ + return this->max_msg_len; +} + METHOD(imv_state_t, change_state, void, private_imv_attestation_state_t *this, TNC_ConnectionState new_state) { @@ -220,8 +257,7 @@ METHOD(imv_state_t, destroy, void, private_imv_attestation_state_t *this) { this->file_meas_requests->destroy_function(this->file_meas_requests, free); - this->components->destroy_offset(this->components, - offsetof(pts_component_t, destroy)); + this->components->destroy_function(this->components, (void *)free_func_comp); this->pts->destroy(this->pts); free(this); } @@ -290,54 +326,74 @@ METHOD(imv_attestation_state_t, get_file_meas_request_count, int, return this->file_meas_requests->get_count(this->file_meas_requests); } -METHOD(imv_attestation_state_t, add_component, void, - private_imv_attestation_state_t *this, pts_component_t *entry) -{ - this->components->insert_last(this->components, entry); -} - -METHOD(imv_attestation_state_t, check_off_component, pts_component_t*, - private_imv_attestation_state_t *this, pts_comp_func_name_t *name) +METHOD(imv_attestation_state_t, create_component, pts_component_t*, + private_imv_attestation_state_t *this, pts_comp_func_name_t *name, + u_int32_t depth, pts_database_t *pts_db) { enumerator_t *enumerator; - pts_component_t *entry, *found = NULL; + func_comp_t *entry, *new_entry; + pts_component_t *component; + bool found = FALSE; enumerator = this->components->create_enumerator(this->components); while (enumerator->enumerate(enumerator, &entry)) { - if (name->equals(name, entry->get_comp_func_name(entry))) + if (name->equals(name, entry->comp->get_comp_func_name(entry->comp))) { - found = entry; - this->components->remove_at(this->components, enumerator); + found = TRUE; break; } } enumerator->destroy(enumerator); - return found; + + if (found) + { + if (name->get_qualifier(name) == entry->qualifier) + { + /* duplicate entry */ + return NULL; + } + new_entry = malloc_thing(func_comp_t); + new_entry->qualifier = name->get_qualifier(name); + new_entry->comp = entry->comp->get_ref(entry->comp); + this->components->insert_last(this->components, new_entry); + return entry->comp; + } + else + { + component = pts_components->create(pts_components, name, depth, pts_db); + if (!component) + { + /* unsupported component */ + return NULL; + } + new_entry = malloc_thing(func_comp_t); + new_entry->qualifier = name->get_qualifier(name); + new_entry->comp = component; + this->components->insert_last(this->components, new_entry); + return component; + } } -METHOD(imv_attestation_state_t, check_off_registrations, void, - private_imv_attestation_state_t *this) +METHOD(imv_attestation_state_t, get_component, pts_component_t*, + private_imv_attestation_state_t *this, pts_comp_func_name_t *name) { enumerator_t *enumerator; - pts_component_t *entry; + func_comp_t *entry; + pts_component_t *found = NULL; enumerator = this->components->create_enumerator(this->components); while (enumerator->enumerate(enumerator, &entry)) { - if (entry->check_off_registrations(entry)) + if (name->equals(name, entry->comp->get_comp_func_name(entry->comp)) && + name->get_qualifier(name) == entry->qualifier) { - this->components->remove_at(this->components, enumerator); - entry->destroy(entry); + found = entry->comp; + break; } } enumerator->destroy(enumerator); -} - -METHOD(imv_attestation_state_t, get_component_count, int, - private_imv_attestation_state_t *this) -{ - return this->components->get_count(this->components); + return found; } METHOD(imv_attestation_state_t, get_measurement_error, bool, @@ -352,6 +408,28 @@ METHOD(imv_attestation_state_t, set_measurement_error, void, this->measurement_error = TRUE; } +METHOD(imv_attestation_state_t, finalize_components, void, + private_imv_attestation_state_t *this) +{ + func_comp_t *entry; + + while (this->components->remove_last(this->components, + (void**)&entry) == SUCCESS) + { + if (!entry->comp->finalize(entry->comp, entry->qualifier)) + { + _set_measurement_error(this); + } + free_func_comp(entry); + } +} + +METHOD(imv_attestation_state_t, components_finalized, bool, + private_imv_attestation_state_t *this) +{ + return this->components->get_count(this->components) == 0; +} + /** * Described in header. */ @@ -367,6 +445,8 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .has_long = _has_long, .has_excl = _has_excl, .set_flags = _set_flags, + .set_max_msg_len = _set_max_msg_len, + .get_max_msg_len = _get_max_msg_len, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, @@ -379,10 +459,10 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .add_file_meas_request = _add_file_meas_request, .check_off_file_meas_request = _check_off_file_meas_request, .get_file_meas_request_count = _get_file_meas_request_count, - .add_component = _add_component, - .check_off_component = _check_off_component, - .check_off_registrations = _check_off_registrations, - .get_component_count = _get_component_count, + .create_component = _create_component, + .get_component = _get_component, + .finalize_components = _finalize_components, + .components_finalized = _components_finalized, .get_measurement_error = _get_measurement_error, .set_measurement_error = _set_measurement_error, }, diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.h b/src/libpts/plugins/imv_attestation/imv_attestation_state.h index 0e2c04da4..901d4b19d 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.h +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -105,32 +106,37 @@ struct imv_attestation_state_t { u_int16_t id, int *file_id, bool *is_dir); /** - * Add an entry to the list of Functional Components waiting for evidence + * Create and add an entry to the list of Functional Components * - * @param entry Functional Component + * @param name Component Functional Name + * @param depth Sub-component Depth + * @param pts_db PTS measurement database + * @return created functional component instance or NULL */ - void (*add_component)(imv_attestation_state_t *this, pts_component_t *entry); + pts_component_t* (*create_component)(imv_attestation_state_t *this, + pts_comp_func_name_t *name, + u_int32_t depth, + pts_database_t *pts_db); /** - * Returns the number of Functional Component waiting for evidence - * - * @return Number of waiting Functional Components - */ - int (*get_component_count)(imv_attestation_state_t *this); - - /** - * Check for presence of Functional Component and remove and return it + * Get a Functional Component with a given name * * @param name Name of the requested Functional Component * @return Functional Component if found, NULL otherwise */ - pts_component_t* (*check_off_component)(imv_attestation_state_t *this, - pts_comp_func_name_t *name); + pts_component_t* (*get_component)(imv_attestation_state_t *this, + pts_comp_func_name_t *name); /** * Tell the Functional Components to finalize any measurement registrations + * and to check if all expected measurements were received + */ + void (*finalize_components)(imv_attestation_state_t *this); + + /** + * Have the Functional Component measurements been finalized? */ - void (*check_off_registrations)(imv_attestation_state_t *this); + bool (*components_finalized)(imv_attestation_state_t *this); /** * Indicates if a file measurement error occurred diff --git a/src/libpts/plugins/imv_attestation/tables.sql b/src/libpts/plugins/imv_attestation/tables.sql index 703557a07..42553bef0 100644 --- a/src/libpts/plugins/imv_attestation/tables.sql +++ b/src/libpts/plugins/imv_attestation/tables.sql @@ -6,6 +6,10 @@ CREATE TABLE files ( type INTEGER NOT NULL, path TEXT NOT NULL ); +DROP INDEX IF EXISTS files_path; +CREATE INDEX files_path ON files ( + path +); DROP TABLE IF EXISTS products; CREATE TABLE products ( @@ -31,6 +35,7 @@ CREATE TABLE file_hashes ( file INTEGER NOT NULL, directory INTEGER DEFAULT 0, product INTEGER NOT NULL, + key INTEGER DEFAULT 0, algo INTEGER NOT NULL, hash BLOB NOT NULL, PRIMARY KEY(file, directory, product, algo) diff --git a/src/libpts/pts/components/ita/ita_comp_ima.c b/src/libpts/pts/components/ita/ita_comp_ima.c index a7da76651..a59732428 100644 --- a/src/libpts/pts/components/ita/ita_comp_ima.c +++ b/src/libpts/pts/components/ita/ita_comp_ima.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -18,6 +17,7 @@ #include "ita_comp_func_name.h" #include "libpts.h" +#include "pts/pts_pcr.h" #include "pts/components/pts_component.h" #include @@ -29,11 +29,25 @@ #include #include -#define IMA_SECURITY_DIR "/sys/kernel/security/tpm0/" -#define IMA_BIOS_MEASUREMENT_PATH IMA_SECURITY_DIR "binary_bios_measurements" -#define IMA_PCR_MAX 16 +#define SECURITY_DIR "/sys/kernel/security/" +#define IMA_BIOS_MEASUREMENTS SECURITY_DIR "tpm0/binary_bios_measurements" +#define IMA_RUNTIME_MEASUREMENTS SECURITY_DIR "ima/binary_runtime_measurements" +#define IMA_PCR 10 +#define IMA_TYPE_LEN 3 +#define IMA_FILENAME_LEN_MAX 255 typedef struct pts_ita_comp_ima_t pts_ita_comp_ima_t; +typedef struct bios_entry_t bios_entry_t; +typedef struct ima_entry_t ima_entry_t; +typedef enum ima_state_t ima_state_t; + +enum ima_state_t { + IMA_STATE_INIT, + IMA_STATE_BIOS, + IMA_STATE_BOOT_AGGREGATE, + IMA_STATE_RUNTIME, + IMA_STATE_END +}; /** * Private data of a pts_ita_comp_ima_t object. @@ -67,52 +81,101 @@ struct pts_ita_comp_ima_t { pts_database_t *pts_db; /** - * Primary key for Component Functional Name database entry + * Primary key for AIK database entry */ - int cid; + int kid; /** - * Primary key for AIK database entry + * Primary key for IMA BIOS Component Functional Name database entry */ - int kid; + int bios_cid; + + /** + * Primary key for IMA Runtime Component Functional Name database entry + */ + int ima_cid; /** - * Component is registering measurements + * Component is registering IMA BIOS measurements */ - bool is_registering; + bool is_bios_registering; + + /** + * Component is registering IMA boot aggregate measurement + */ + bool is_ima_registering; + + /** + * Measurement sequence number + */ + int seq_no; /** - * IMA BIOS measurement time + * Expected IMA BIOS measurement count */ - time_t bios_measurement_time; + int bios_count; /** * IMA BIOS measurements */ - linked_list_t *list; + linked_list_t *bios_list; /** - * Expected measurement count + * IMA runtime file measurements + */ + linked_list_t *ima_list; + + /** + * Whether to send pcr_before and pcr_after info + */ + bool pcr_info; + + /** + * IMA measurement time + */ + time_t measurement_time; + + /** + * IMA state machine + */ + ima_state_t state; + + /** + * Total number of component measurements */ int count; /** - * Measurement sequence number + * Number of successful component measurements */ - int seq_no; + int count_ok; /** - * Shadow PCR registers + * Number of unknown component measurements */ - chunk_t pcrs[IMA_PCR_MAX]; -}; + int count_unknown; -typedef struct entry_t entry_t; + /** + * Number of differing component measurements + */ + int count_differ; + + /** + * Number of failed component measurements + */ + int count_failed; + + /** + * Reference count + */ + refcount_t ref; + +}; /** - * Linux IMA measurement entry + * Linux IMA BIOS measurement entry */ -struct entry_t { +struct bios_entry_t { /** * PCR register @@ -126,21 +189,48 @@ struct entry_t { }; /** - * Free an entry_t object + * Linux IMA runtime file measurement entry + */ +struct ima_entry_t { + + /** + * SHA1 measurement hash + */ + chunk_t measurement; + + /** + * absolute path of executable files or basename of dynamic libraries + */ + char *filename; +}; + +/** + * Free a bios_entry_t object + */ +static void free_bios_entry(bios_entry_t *this) +{ + free(this->measurement.ptr); + free(this); +} + +/** + * Free an ima_entry_t object */ -static void free_entry(entry_t *this) +static void free_ima_entry(ima_entry_t *this) { free(this->measurement.ptr); + free(this->filename); free(this); } /** * Load a PCR measurement file and determine the creation date */ -static bool load_measurements(char *file, linked_list_t *list, time_t *created) +static bool load_bios_measurements(char *file, linked_list_t *list, + time_t *created) { u_int32_t pcr, num, len; - entry_t *entry; + bios_entry_t *entry; struct stat st; ssize_t res; int fd; @@ -148,13 +238,13 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created) fd = open(file, O_RDONLY); if (fd == -1) { - DBG1(DBG_PTS, " opening '%s' failed: %s", file, strerror(errno)); + DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno)); return FALSE; } if (fstat(fd, &st) == -1) { - DBG1(DBG_PTS, " getting statistics of '%s' failed: %s", file, + DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, strerror(errno)); close(fd); return FALSE; @@ -167,12 +257,12 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created) if (res == 0) { DBG2(DBG_PTS, "loaded bios measurements '%s' (%d entries)", - file, list->get_count(list)); + file, list->get_count(list)); close(fd); return TRUE; } - entry = malloc_thing(entry_t); + entry = malloc_thing(bios_entry_t); entry->pcr = pcr; entry->measurement = chunk_alloc(HASH_SIZE_SHA1); @@ -199,12 +289,188 @@ static bool load_measurements(char *file, linked_list_t *list, time_t *created) list->insert_last(list, entry); } - DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", - file, strerror(errno)); + DBG1(DBG_PTS, "loading bios measurements '%s' failed: %s", file, + strerror(errno)); + close(fd); + return FALSE; +} + +/** + * Load an IMA runtime measurement file and determine the creation and + * update dates + */ +static bool load_runtime_measurements(char *file, linked_list_t *list, + time_t *created) +{ + u_int32_t pcr, len; + ima_entry_t *entry; + char type[IMA_TYPE_LEN]; + struct stat st; + ssize_t res; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) + { + DBG1(DBG_PTS, "opening '%s' failed: %s", file, strerror(errno)); + return TRUE; + } + + if (fstat(fd, &st) == -1) + { + DBG1(DBG_PTS, "getting statistics of '%s' failed: %s", file, + strerror(errno)); + close(fd); + return FALSE; + } + *created = st.st_ctime; + + while (TRUE) + { + res = read(fd, &pcr, 4); + if (res == 0) + { + DBG2(DBG_PTS, "loaded ima measurements '%s' (%d entries)", + file, list->get_count(list)); + close(fd); + return TRUE; + } + + entry = malloc_thing(ima_entry_t); + entry->measurement = chunk_alloc(HASH_SIZE_SHA1); + entry->filename = NULL; + + if (res != 4 || pcr != IMA_PCR) + { + break; + } + if (read(fd, entry->measurement.ptr, HASH_SIZE_SHA1) != HASH_SIZE_SHA1) + { + break; + } + if (read(fd, &len, 4) != 4 || len != IMA_TYPE_LEN) + { + break; + } + if (read(fd, type, IMA_TYPE_LEN) != IMA_TYPE_LEN || + memcmp(type, "ima", IMA_TYPE_LEN)) + { + break; + } + if (lseek(fd, HASH_SIZE_SHA1, SEEK_CUR) == -1) + { + break; + } + if (read(fd, &len, 4) != 4) + { + break; + } + entry->filename = malloc(len + 1); + if (read(fd, entry->filename, len) != len) + { + break; + } + entry->filename[len] = '\0'; + + list->insert_last(list, entry); + } + + DBG1(DBG_PTS, "loading ima measurements '%s' failed: %s", + file, strerror(errno)); close(fd); return FALSE; } +/** + * Extend measurement into PCR an create evidence + */ +static pts_comp_evidence_t* extend_pcr(pts_ita_comp_ima_t* this, + u_int8_t qualifier, pts_pcr_t *pcrs, + u_int32_t pcr, chunk_t measurement) +{ + size_t pcr_len; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; + pts_comp_func_name_t *name; + pts_comp_evidence_t *evidence; + chunk_t pcr_before = chunk_empty, pcr_after = chunk_empty; + + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; + pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + + if (this->pcr_info) + { + pcr_before = chunk_clone(pcrs->get(pcrs, pcr)); + } + pcr_after = pcrs->extend(pcrs, pcr, measurement); + if (!pcr_after.ptr) + { + free(pcr_before.ptr); + return NULL; + } + name = this->name->clone(this->name); + name->set_qualifier(name, qualifier); + evidence = pts_comp_evidence_create(name, this->depth, pcr, hash_algo, + pcr_transform, this->measurement_time, measurement); + if (this->pcr_info) + { + pcr_after =chunk_clone(pcrs->get(pcrs, pcr)); + evidence->set_pcr_info(evidence, pcr_before, pcr_after); + } + return evidence; +} + +/** + * Compute and check boot aggregate value by hashing PCR0 to PCR7 + */ +static bool check_boot_aggregate(pts_pcr_t *pcrs, chunk_t measurement) +{ + u_int32_t i; + u_char filename_buffer[IMA_FILENAME_LEN_MAX + 1]; + u_char pcr_buffer[HASH_SIZE_SHA1]; + chunk_t file_name, boot_aggregate; + hasher_t *hasher; + bool success, pcr_ok = TRUE; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, HASH_SHA1); + return FALSE; + } + for (i = 0; i < 8 && pcr_ok; i++) + { + pcr_ok = hasher->get_hash(hasher, pcrs->get(pcrs, i), NULL); + } + if (pcr_ok) + { + boot_aggregate = chunk_create(pcr_buffer, sizeof(pcr_buffer)); + memset(filename_buffer, 0, sizeof(filename_buffer)); + strcpy(filename_buffer, "boot_aggregate"); + file_name = chunk_create (filename_buffer, sizeof(filename_buffer)); + + pcr_ok = hasher->get_hash(hasher, chunk_empty, pcr_buffer) && + hasher->get_hash(hasher, boot_aggregate, NULL) && + hasher->get_hash(hasher, file_name, boot_aggregate.ptr); + } + hasher->destroy(hasher); + + if (pcr_ok) + { + success = chunk_equals(boot_aggregate, measurement); + DBG1(DBG_PTS, "boot aggregate value is %scorrect", + success ? "":"in"); + return success; + } + else + { + DBG1(DBG_PTS, "failed to compute boot aggregate value"); + return FALSE; + } +} + METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, pts_ita_comp_ima_t *this) { @@ -224,193 +490,446 @@ METHOD(pts_component_t, get_depth, u_int32_t, } METHOD(pts_component_t, measure, status_t, - pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t **evidence) + pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) { - pts_comp_evidence_t *evid; - chunk_t pcr_before, pcr_after; - pts_pcr_transform_t pcr_transform; - pts_meas_algorithms_t hash_algo; - size_t pcr_len; - entry_t *entry; - hasher_t *hasher; + bios_entry_t *bios_entry; + ima_entry_t *ima_entry; + pts_pcr_t *pcrs; + pts_comp_evidence_t *evid = NULL; + status_t status; - hash_algo = PTS_MEAS_ALGO_SHA1; - pcr_len = pts->get_pcr_len(pts); - pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); + pcrs = pts->get_pcrs(pts); - if (this->list->get_count(this->list) == 0) + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) { - if (!load_measurements(IMA_BIOS_MEASUREMENT_PATH, this->list, - &this->bios_measurement_time)) + switch (this->state) { - return FAILED; + case IMA_STATE_INIT: + if (!load_bios_measurements(IMA_BIOS_MEASUREMENTS, + this->bios_list, &this->measurement_time)) + { + return FAILED; + } + this->bios_count = this->bios_list->get_count(this->bios_list); + this->state = IMA_STATE_BIOS; + /* fall through to next state */ + case IMA_STATE_BIOS: + status = this->bios_list->remove_first(this->bios_list, + (void**)&bios_entry); + if (status != SUCCESS) + { + DBG1(DBG_PTS, "could not retrieve bios measurement entry"); + return status; + } + evid = extend_pcr(this, qualifier, pcrs, bios_entry->pcr, + bios_entry->measurement); + free(bios_entry); + + this->state = this->bios_list->get_count(this->bios_list) ? + IMA_STATE_BIOS : IMA_STATE_INIT; + break; + default: + return FAILED; } } - - if (this->list->remove_first(this->list, (void**)&entry) != SUCCESS) + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) + { + switch (this->state) + { + case IMA_STATE_INIT: + if (!load_runtime_measurements(IMA_RUNTIME_MEASUREMENTS, + this->ima_list, &this->measurement_time)) + { + return FAILED; + } + this->state = IMA_STATE_BOOT_AGGREGATE; + /* fall through to next state */ + case IMA_STATE_BOOT_AGGREGATE: + case IMA_STATE_RUNTIME: + status = this->ima_list->remove_first(this->ima_list, + (void**)&ima_entry); + if (status != SUCCESS) + { + DBG1(DBG_PTS, "could not retrieve ima measurement entry"); + return status; + } + if (this->state == IMA_STATE_BOOT_AGGREGATE && this->bios_count) + { + if (!check_boot_aggregate(pcrs, ima_entry->measurement)) + { + return FAILED; + } + } + evid = extend_pcr(this, qualifier, pcrs, IMA_PCR, + ima_entry->measurement); + if (evid) + { + evid->set_validation(evid, PTS_COMP_EVID_VALIDATION_PASSED, + ima_entry->filename); + } + free(ima_entry->filename); + free(ima_entry); + + this->state = this->ima_list->get_count(this->ima_list) ? + IMA_STATE_RUNTIME : IMA_STATE_END; + break; + default: + return FAILED; + } + } + else { - DBG1(DBG_PTS, "could not retrieve measurement entry"); + DBG1(DBG_PTS, "unsupported functional component name qualifier"); return FAILED; } - - pcr_before = chunk_clone(this->pcrs[entry->pcr]); - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - hasher->get_hash(hasher, pcr_before, NULL); - hasher->get_hash(hasher, entry->measurement, this->pcrs[entry->pcr].ptr); - hasher->destroy(hasher); - - pcr_after = chunk_clone(this->pcrs[entry->pcr]); - evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), - this->depth, entry->pcr, hash_algo, pcr_transform, - this->bios_measurement_time, entry->measurement); - evid->set_pcr_info(evid, pcr_before, pcr_after); - - free(entry); + *evidence = evid; + if (!evid) + { + return FAILED; + } - return (this->list->get_count(this->list)) ? NEED_MORE : SUCCESS; + return (this->state == IMA_STATE_INIT || this->state == IMA_STATE_END) ? + SUCCESS : NEED_MORE; } METHOD(pts_component_t, verify, status_t, - pts_ita_comp_ima_t *this, pts_t *pts, pts_comp_evidence_t *evidence) + pts_ita_comp_ima_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t *evidence) { bool has_pcr_info; - u_int32_t extended_pcr, vid, name; + u_int32_t pcr, vid, name; enum_name_t *names; pts_meas_algorithms_t algo; pts_pcr_transform_t transform; + pts_pcr_t *pcrs; time_t measurement_time; chunk_t measurement, pcr_before, pcr_after; + status_t status; + char *uri; - measurement = evidence->get_measurement(evidence, &extended_pcr, - &algo, &transform, &measurement_time); - + /* some first time initializations */ if (!this->keyid.ptr) { if (!pts->get_aik_keyid(pts, &this->keyid)) { + DBG1(DBG_PTS, "AIK keyid not available"); return FAILED; } this->keyid = chunk_clone(this->keyid); - if (!this->pts_db) { DBG1(DBG_PTS, "pts database not available"); return FAILED; } - if (this->pts_db->get_comp_measurement_count(this->pts_db, - this->name, this->keyid, algo, - &this->cid, &this->kid, &this->count) != SUCCESS) - { - return FAILED; - } - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); + } - if (this->count) - { - DBG1(DBG_PTS, "checking %d %N '%N' functional component evidence " - "measurements", this->count, pen_names, vid, names, name); - } - else + pcrs = pts->get_pcrs(pts); + measurement = evidence->get_measurement(evidence, &pcr, &algo, &transform, + &measurement_time); + + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) + { + switch (this->state) { - DBG1(DBG_PTS, "registering %N '%N' functional component evidence " - "measurements", pen_names, vid, names, name); - this->is_registering = TRUE; + case IMA_STATE_INIT: + this->name->set_qualifier(this->name, qualifier); + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->keyid, algo, &this->bios_cid, + &this->kid, &this->bios_count); + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); + if (status != SUCCESS) + { + return status; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->bios_count) + { + DBG1(DBG_PTS, "checking %d %N '%N' BIOS evidence measurements", + this->bios_count, pen_names, vid, names, name); + } + else + { + DBG1(DBG_PTS, "registering %N '%N' BIOS evidence measurements", + pen_names, vid, names, name); + this->is_bios_registering = TRUE; + } + + this->state = IMA_STATE_BIOS; + /* fall through to next state */ + case IMA_STATE_BIOS: + if (this->is_bios_registering) + { + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->bios_cid, this->kid, + ++this->seq_no, pcr, algo); + if (status != SUCCESS) + { + return status; + } + this->bios_count = this->seq_no + 1; + } + else + { + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->bios_cid, this->kid, + ++this->seq_no, pcr, algo); + if (status != SUCCESS) + { + return status; + } + } + break; + default: + return FAILED; } } - - if (this->is_registering) + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) { - if (this->pts_db->insert_comp_measurement(this->pts_db, measurement, - this->cid, this->kid, ++this->seq_no, - extended_pcr, algo) != SUCCESS) + int ima_count; + + switch (this->state) { - return FAILED; + case IMA_STATE_BIOS: + if (!check_boot_aggregate(pcrs, measurement)) + { + this->state = IMA_STATE_RUNTIME; + return FAILED; + } + this->state = IMA_STATE_INIT; + /* fall through to next state */ + case IMA_STATE_INIT: + this->name->set_qualifier(this->name, qualifier); + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->keyid, algo, + &this->ima_cid, &this->kid, &ima_count); + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); + if (status != SUCCESS) + { + return status; + } + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (ima_count) + { + DBG1(DBG_PTS, "checking %N '%N' boot aggregate evidence " + "measurement", pen_names, vid, names, name); + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->ima_cid, + this->kid, 1, pcr, algo); + } + else + { + DBG1(DBG_PTS, "registering %N '%N' boot aggregate evidence " + "measurement", pen_names, vid, names, name); + this->is_ima_registering = TRUE; + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->ima_cid, + this->kid, 1, pcr, algo); + } + this->state = IMA_STATE_RUNTIME; + + if (status != SUCCESS) + { + return status; + } + break; + case IMA_STATE_RUNTIME: + this->count++; + if (evidence->get_validation(evidence, &uri) != + PTS_COMP_EVID_VALIDATION_PASSED) + { + DBG1(DBG_PTS, "policy URI could no be retrieved"); + this->count_failed++; + return FAILED; + } + status = this->pts_db->check_file_measurement(this->pts_db, + pts->get_platform_info(pts), + PTS_MEAS_ALGO_SHA1_IMA, + measurement, uri); + switch (status) + { + case SUCCESS: + DBG3(DBG_PTS, "%#B for '%s' is ok", + &measurement, uri); + this->count_ok++; + break; + case NOT_FOUND: + DBG2(DBG_PTS, "%#B for '%s' not found", + &measurement, uri); + this->count_unknown++; + break; + case VERIFY_ERROR: + DBG1(DBG_PTS, "%#B for '%s' differs", + &measurement, uri); + this->count_differ++; + break; + case FAILED: + default: + DBG1(DBG_PTS, "%#B for '%s' failed", + &measurement, uri); + this->count_failed++; + } + break; + default: + return FAILED; } - this->count = this->seq_no + 1; } else { - if (this->pts_db->check_comp_measurement(this->pts_db, measurement, - this->cid, this->kid, ++this->seq_no, - extended_pcr, algo) != SUCCESS) - { - return FAILED; - } + DBG1(DBG_PTS, "unsupported functional component name qualifier"); + return FAILED; } has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + if (!chunk_equals(pcr_before, pcrs->get(pcrs, pcr))) { - return FAILED; + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", + pcr); + } + if (pcrs->set(pcrs, pcr, pcr_after)) + { + return SUCCESS; } } - - return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; + else + { + pcr_after = pcrs->extend(pcrs, pcr, measurement); + if (pcr_after.ptr) + { + return SUCCESS; + } + } + return FAILED; } -METHOD(pts_component_t, check_off_registrations, bool, - pts_ita_comp_ima_t *this) +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_ima_t *this, u_int8_t qualifier) { u_int32_t vid, name; enum_name_t *names; + bool success = TRUE; - if (!this->is_registering) + this->name->set_qualifier(this->name, qualifier); + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED)) { - return FALSE; + /* finalize BIOS measurements */ + if (this->is_bios_registering) + { + /* close registration */ + this->is_bios_registering = FALSE; + + DBG1(DBG_PTS, "registered %d %N '%N' BIOS evidence measurements", + this->seq_no, pen_names, vid, names, name); + } + else if (this->seq_no < this->bios_count) + { + DBG1(DBG_PTS, "%d of %d %N '%N' BIOS evidence measurements missing", + this->bios_count - this->seq_no, this->bios_count, + pen_names, vid, names, name); + success = FALSE; + } } + else if (qualifier == (PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_OS)) + { + /* finalize IMA file measurements */ + if (this->is_ima_registering) + { + /* close registration */ + this->is_ima_registering = FALSE; - /* Finalize registration */ - this->is_registering = FALSE; + DBG1(DBG_PTS, "registered %N '%N' boot aggregate evidence " + "measurement", pen_names, vid, names, name); + } + if (this->count) + { + DBG1(DBG_PTS, "processed %d %N '%N' file evidence measurements: " + "%d ok, %d unknown, %d differ, %d failed", + this->count, pen_names, vid, names, name, + this->count_ok, this->count_unknown, + this->count_differ, this->count_failed); + success = !this->count_differ && !this->count_failed; + } + } + else + { + DBG1(DBG_PTS, "unsupported functional component name qualifier"); + success = FALSE; + } + this->name->set_qualifier(this->name, PTS_QUALIFIER_UNKNOWN); - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); - DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " - "measurements", this->seq_no, pen_names, vid, names, name); - return TRUE; + return success; +} + +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_ima_t *this) +{ + ref_get(&this->ref); + return &this->public; } METHOD(pts_component_t, destroy, void, pts_ita_comp_ima_t *this) { - int i, count; + int count; u_int32_t vid, name; enum_name_t *names; - for (i = 0; i < IMA_PCR_MAX; i++) - { - free(this->pcrs[i].ptr); - } - if (this->is_registering) + if (ref_put(&this->ref)) { - count = this->pts_db->delete_comp_measurements(this->pts_db, - this->cid, this->kid); vid = this->name->get_vendor_id(this->name); name = this->name->get_name(this->name); names = pts_components->get_comp_func_names(pts_components, vid); - DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " - "evidence measurements", count, pen_names, vid, names, name); + + if (this->is_bios_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->bios_cid, this->kid); + DBG1(DBG_PTS, "deleted %d registered %N '%N' BIOS evidence " + "measurements", count, pen_names, vid, names, name); + } + if (this->is_ima_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->ima_cid, this->kid); + DBG1(DBG_PTS, "deleted registered %N '%N' boot aggregate evidence " + "measurement", pen_names, vid, names, name); + } + this->bios_list->destroy_function(this->bios_list, + (void *)free_bios_entry); + this->ima_list->destroy_function(this->ima_list, + (void *)free_ima_entry); + this->name->destroy(this->name); + free(this->keyid.ptr); + free(this); } - this->list->destroy_function(this->list, (void *)free_entry); - this->name->destroy(this->name); - free(this->keyid.ptr); - free(this); } /** * See header */ -pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t *pts_ita_comp_ima_create(u_int32_t depth, pts_database_t *pts_db) { pts_ita_comp_ima_t *this; - int i; INIT(this, .public = { @@ -419,21 +938,21 @@ pts_component_t *pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, .get_depth = _get_depth, .measure = _measure, .verify = _verify, - .check_off_registrations = _check_off_registrations, + .finalize = _finalize, + .get_ref = _get_ref, .destroy = _destroy, }, .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_IMA, - qualifier), + PTS_QUALIFIER_UNKNOWN), .depth = depth, .pts_db = pts_db, - .list = linked_list_create(), + .bios_list = linked_list_create(), + .ima_list = linked_list_create(), + .pcr_info = lib->settings->get_bool(lib->settings, + "libimcv.plugins.imc-attestation.pcr_info", TRUE), + .ref = 1, ); - for (i = 0; i < IMA_PCR_MAX; i++) - { - this->pcrs[i] = chunk_alloc(HASH_SIZE_SHA1); - memset(this->pcrs[i].ptr, 0x00, HASH_SIZE_SHA1); - } return &this->public; } diff --git a/src/libpts/pts/components/ita/ita_comp_ima.h b/src/libpts/pts/components/ita/ita_comp_ima.h index 1ca27e6f0..546d0a4b2 100644 --- a/src/libpts/pts/components/ita/ita_comp_ima.h +++ b/src/libpts/pts/components/ita/ita_comp_ima.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,11 +26,10 @@ /** * Create a PTS ITS Functional Component object * - * @param qualifier PTS Component Functional Name Qualifier * @param depth Sub-component depth * @param pts_db PTS measurement database */ -pts_component_t* pts_ita_comp_ima_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t* pts_ita_comp_ima_create(u_int32_t depth, pts_database_t *pts_db); #endif /** PTS_ITA_COMP_IMA_H_ @}*/ diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.c b/src/libpts/pts/components/ita/ita_comp_tboot.c index a85de8cd8..9deeb19b5 100644 --- a/src/libpts/pts/components/ita/ita_comp_tboot.c +++ b/src/libpts/pts/components/ita/ita_comp_tboot.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -86,6 +85,11 @@ struct pts_ita_comp_tboot_t { */ int seq_no; + /** + * Reference count + */ + refcount_t ref; + }; METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, @@ -107,15 +111,18 @@ METHOD(pts_component_t, get_depth, u_int32_t, } METHOD(pts_component_t, measure, status_t, - pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t **evidence) + pts_ita_comp_tboot_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) + { + size_t pcr_len; + pts_pcr_t *pcrs; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; pts_comp_evidence_t *evid; char *meas_hex, *pcr_before_hex, *pcr_after_hex; chunk_t measurement, pcr_before, pcr_after; - size_t hash_size, pcr_len; u_int32_t extended_pcr; - pts_pcr_transform_t pcr_transform; - pts_meas_algorithms_t hash_algo; switch (this->seq_no++) { @@ -149,9 +156,8 @@ METHOD(pts_component_t, measure, status_t, return FAILED; } - hash_algo = pts->get_meas_algorithm(pts); - hash_size = pts_meas_algo_hash_size(hash_algo); - pcr_len = pts->get_pcr_len(pts); + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); /* get and check the measurement data */ @@ -162,35 +168,40 @@ METHOD(pts_component_t, measure, status_t, pcr_after = chunk_from_hex( chunk_create(pcr_after_hex, strlen(pcr_after_hex)), NULL); if (pcr_before.len != pcr_len || pcr_after.len != pcr_len || - measurement.len != hash_size) + measurement.len != pcr_len) { - DBG1(DBG_PTS, "TBOOT measurement or pcr data have the wrong size"); + DBG1(DBG_PTS, "TBOOT measurement or PCR data have the wrong size"); free(measurement.ptr); free(pcr_before.ptr); free(pcr_after.ptr); return FAILED; } + pcrs = pts->get_pcrs(pts); + pcrs->set(pcrs, extended_pcr, pcr_after); evid = *evidence = pts_comp_evidence_create(this->name->clone(this->name), - this->depth, extended_pcr, - hash_algo, pcr_transform, - this->measurement_time, measurement); + this->depth, extended_pcr, hash_algo, pcr_transform, + this->measurement_time, measurement); evid->set_pcr_info(evid, pcr_before, pcr_after); return (this->seq_no < 2) ? NEED_MORE : SUCCESS; } METHOD(pts_component_t, verify, status_t, - pts_ita_comp_tboot_t *this, pts_t *pts, pts_comp_evidence_t *evidence) + pts_ita_comp_tboot_t *this, u_int8_t qualifier,pts_t *pts, + pts_comp_evidence_t *evidence) { bool has_pcr_info; u_int32_t extended_pcr, vid, name; enum_name_t *names; pts_meas_algorithms_t algo; pts_pcr_transform_t transform; + pts_pcr_t *pcrs; time_t measurement_time; chunk_t measurement, pcr_before, pcr_after; + status_t status; + pcrs = pts->get_pcrs(pts); measurement = evidence->get_measurement(evidence, &extended_pcr, &algo, &transform, &measurement_time); @@ -207,11 +218,12 @@ METHOD(pts_component_t, verify, status_t, DBG1(DBG_PTS, "pts database not available"); return FAILED; } - if (this->pts_db->get_comp_measurement_count(this->pts_db, - this->name, this->keyid, algo, - &this->cid, &this->kid, &this->count) != SUCCESS) + status = this->pts_db->get_comp_measurement_count(this->pts_db, + this->name, this->keyid, algo, &this->cid, + &this->kid, &this->count); + if (status != SUCCESS) { - return FAILED; + return status; } vid = this->name->get_vendor_id(this->name); name = this->name->get_name(this->name); @@ -232,58 +244,79 @@ METHOD(pts_component_t, verify, status_t, if (this->is_registering) { - if (this->pts_db->insert_comp_measurement(this->pts_db, measurement, - this->cid, this->kid, ++this->seq_no, - extended_pcr, algo) != SUCCESS) + status = this->pts_db->insert_comp_measurement(this->pts_db, + measurement, this->cid, this->kid, + ++this->seq_no, extended_pcr, algo); + if (status != SUCCESS) { - return FAILED; + return status; } this->count = this->seq_no + 1; } else { - if (this->pts_db->check_comp_measurement(this->pts_db, measurement, - this->cid, this->kid, ++this->seq_no, - extended_pcr, algo) != SUCCESS) + status = this->pts_db->check_comp_measurement(this->pts_db, + measurement, this->cid, this->kid, + ++this->seq_no, extended_pcr, algo); + if (status != SUCCESS) { - return FAILED; + return status; } } has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) { - return FAILED; + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to register value", + extended_pcr); + } + if (pcrs->set(pcrs, extended_pcr, pcr_after)) + { + return SUCCESS; } } - return (this->seq_no < this->count) ? NEED_MORE : SUCCESS; + return SUCCESS; } -METHOD(pts_component_t, check_off_registrations, bool, - pts_ita_comp_tboot_t *this) +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_tboot_t *this, u_int8_t qualifier) { u_int32_t vid, name; enum_name_t *names; - if (!this->is_registering) + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + + if (this->is_registering) { + /* close registration */ + this->is_registering = FALSE; + + DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " + "measurements", this->seq_no, pen_names, vid, names, name); + } + else if (this->seq_no < this->count) + { + DBG1(DBG_PTS, "%d of %d %N '%N' functional component evidence " + "measurements missing", this->count - this->seq_no, + this->count, pen_names, vid, names, name); return FALSE; } - /* Finalize registration */ - this->is_registering = FALSE; - - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); - DBG1(DBG_PTS, "registered %d %N '%N' functional component evidence " - "measurements", this->seq_no, pen_names, vid, names, name); return TRUE; } +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_tboot_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + METHOD(pts_component_t, destroy, void, pts_ita_comp_tboot_t *this) { @@ -291,25 +324,28 @@ METHOD(pts_component_t, destroy, void, u_int32_t vid, name; enum_name_t *names; - if (this->is_registering) + if (ref_put(&this->ref)) { - count = this->pts_db->delete_comp_measurements(this->pts_db, - this->cid, this->kid); - vid = this->name->get_vendor_id(this->name); - name = this->name->get_name(this->name); - names = pts_components->get_comp_func_names(pts_components, vid); - DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " - "evidence measurements", count, pen_names, vid, names, name); + if (this->is_registering) + { + count = this->pts_db->delete_comp_measurements(this->pts_db, + this->cid, this->kid); + vid = this->name->get_vendor_id(this->name); + name = this->name->get_name(this->name); + names = pts_components->get_comp_func_names(pts_components, vid); + DBG1(DBG_PTS, "deleted %d registered %N '%N' functional component " + "evidence measurements", count, pen_names, vid, names, name); + } + this->name->destroy(this->name); + free(this->keyid.ptr); + free(this); } - this->name->destroy(this->name); - free(this->keyid.ptr); - free(this); } /** * See header */ -pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t *pts_ita_comp_tboot_create(u_int32_t depth, pts_database_t *pts_db) { pts_ita_comp_tboot_t *this; @@ -321,13 +357,16 @@ pts_component_t *pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth, .get_depth = _get_depth, .measure = _measure, .verify = _verify, - .check_off_registrations = _check_off_registrations, + .finalize = _finalize, + .get_ref = _get_ref, .destroy = _destroy, }, .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TBOOT, - qualifier), + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED), .depth = depth, .pts_db = pts_db, + .ref = 1, ); return &this->public; diff --git a/src/libpts/pts/components/ita/ita_comp_tboot.h b/src/libpts/pts/components/ita/ita_comp_tboot.h index 39554fbc7..1e1a14831 100644 --- a/src/libpts/pts/components/ita/ita_comp_tboot.h +++ b/src/libpts/pts/components/ita/ita_comp_tboot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,11 +26,10 @@ /** * Create a PTS ITS Functional Component object * - * @param qualifier PTS Component Functional Name Qualifier * @param depth Sub-component depth * @param pts_db PTS measurement database */ -pts_component_t* pts_ita_comp_tboot_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t* pts_ita_comp_tboot_create(u_int32_t depth, pts_database_t *pts_db); #endif /** PTS_ITA_COMP_TBOOT_H_ @}*/ diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.c b/src/libpts/pts/components/ita/ita_comp_tgrub.c index 0dfd5fd41..986f7ace2 100644 --- a/src/libpts/pts/components/ita/ita_comp_tgrub.c +++ b/src/libpts/pts/components/ita/ita_comp_tgrub.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -50,6 +49,12 @@ struct pts_ita_comp_tgrub_t { */ pts_database_t *pts_db; + + /** + * Reference count + */ + refcount_t ref; + }; METHOD(pts_component_t, get_comp_func_name, pts_comp_func_name_t*, @@ -71,15 +76,16 @@ METHOD(pts_component_t, get_depth, u_int32_t, } METHOD(pts_component_t, measure, status_t, - pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t **evidence) + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t **evidence) { + size_t pcr_len; + pts_pcr_transform_t pcr_transform; + pts_meas_algorithms_t hash_algo; pts_comp_evidence_t *evid; u_int32_t extended_pcr; time_t measurement_time; chunk_t measurement, pcr_before, pcr_after; - pts_pcr_transform_t pcr_transform; - pts_meas_algorithms_t hash_algo; - size_t hash_size, pcr_len; /* Provisional implementation for TGRUB */ extended_pcr = PCR_DEBUG; @@ -91,12 +97,11 @@ METHOD(pts_component_t, measure, status_t, return FAILED; } - hash_algo = pts->get_meas_algorithm(pts); - hash_size = pts_meas_algo_hash_size(hash_algo); - pcr_len = pts->get_pcr_len(pts); + hash_algo = PTS_MEAS_ALGO_SHA1; + pcr_len = HASH_SIZE_SHA1; pcr_transform = pts_meas_algo_to_pcr_transform(hash_algo, pcr_len); - measurement = chunk_alloc(hash_size); + measurement = chunk_alloc(pcr_len); memset(measurement.ptr, 0x00, measurement.len); pcr_before = chunk_alloc(pcr_len); @@ -112,15 +117,18 @@ METHOD(pts_component_t, measure, status_t, } METHOD(pts_component_t, verify, status_t, - pts_ita_comp_tgrub_t *this, pts_t *pts, pts_comp_evidence_t *evidence) + pts_ita_comp_tgrub_t *this, u_int8_t qualifier, pts_t *pts, + pts_comp_evidence_t *evidence) { bool has_pcr_info; u_int32_t extended_pcr; pts_meas_algorithms_t algo; pts_pcr_transform_t transform; + pts_pcr_t *pcrs; time_t measurement_time; chunk_t measurement, pcr_before, pcr_after; + pcrs = pts->get_pcrs(pts); measurement = evidence->get_measurement(evidence, &extended_pcr, &algo, &transform, &measurement_time); if (extended_pcr != PCR_DEBUG) @@ -133,32 +141,46 @@ METHOD(pts_component_t, verify, status_t, has_pcr_info = evidence->get_pcr_info(evidence, &pcr_before, &pcr_after); if (has_pcr_info) { - if (!pts->add_pcr(pts, extended_pcr, pcr_before, pcr_after)) + if (!chunk_equals(pcr_before, pcrs->get(pcrs, extended_pcr))) { - return FAILED; + DBG1(DBG_PTS, "PCR %2u: pcr_before is not equal to pcr value"); + } + if (pcrs->set(pcrs, extended_pcr, pcr_after)) + { + return SUCCESS; } } return SUCCESS; } -METHOD(pts_component_t, check_off_registrations, bool, - pts_ita_comp_tgrub_t *this) +METHOD(pts_component_t, finalize, bool, + pts_ita_comp_tgrub_t *this, u_int8_t qualifier) { return FALSE; } +METHOD(pts_component_t, get_ref, pts_component_t*, + pts_ita_comp_tgrub_t *this) +{ + ref_get(&this->ref); + return &this->public; +} + METHOD(pts_component_t, destroy, void, pts_ita_comp_tgrub_t *this) { - this->name->destroy(this->name); - free(this); + if (ref_put(&this->ref)) + { + this->name->destroy(this->name); + free(this); + } } /** * See header */ -pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t *pts_ita_comp_tgrub_create(u_int32_t depth, pts_database_t *pts_db) { pts_ita_comp_tgrub_t *this; @@ -170,13 +192,16 @@ pts_component_t *pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth, .get_depth = _get_depth, .measure = _measure, .verify = _verify, - .check_off_registrations = _check_off_registrations, + .finalize = _finalize, + .get_ref = _get_ref, .destroy = _destroy, }, .name = pts_comp_func_name_create(PEN_ITA, PTS_ITA_COMP_FUNC_NAME_TGRUB, - qualifier), + PTS_ITA_QUALIFIER_FLAG_KERNEL | + PTS_ITA_QUALIFIER_TYPE_TRUSTED), .depth = depth, .pts_db = pts_db, + .ref = 1, ); return &this->public; diff --git a/src/libpts/pts/components/ita/ita_comp_tgrub.h b/src/libpts/pts/components/ita/ita_comp_tgrub.h index 52ecc325c..59913c82d 100644 --- a/src/libpts/pts/components/ita/ita_comp_tgrub.h +++ b/src/libpts/pts/components/ita/ita_comp_tgrub.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -26,11 +26,10 @@ /** * Create a PTS ITS Functional Component object * - * @param qualifier PTS Component Functional Name Qualifier * @param depth Sub-component depth * @param pts_db PTS measurement database */ -pts_component_t* pts_ita_comp_tgrub_create(u_int8_t qualifier, u_int32_t depth, +pts_component_t* pts_ita_comp_tgrub_create(u_int32_t depth, pts_database_t *pts_db); #endif /** PTS_ITA_COMP_TGRUB_H_ @}*/ diff --git a/src/libpts/pts/components/pts_comp_evidence.c b/src/libpts/pts/components/pts_comp_evidence.c index 9eb8dae75..050717472 100644 --- a/src/libpts/pts/components/pts_comp_evidence.c +++ b/src/libpts/pts/components/pts_comp_evidence.c @@ -87,7 +87,7 @@ struct private_pts_comp_evidence_t { /** * Verification Policy URI */ - chunk_t policy_uri; + char *policy_uri; }; @@ -152,12 +152,12 @@ METHOD(pts_comp_evidence_t, set_pcr_info, void, this->pcr_before = pcr_before; this->pcr_after = pcr_after; - DBG2(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before); - DBG2(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after); + DBG3(DBG_PTS, "PCR %2d before value : %#B", this->extended_pcr, &pcr_before); + DBG3(DBG_PTS, "PCR %2d after value : %#B", this->extended_pcr, &pcr_after); } METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t, - private_pts_comp_evidence_t *this, chunk_t *uri) + private_pts_comp_evidence_t *this, char **uri) { if (uri) { @@ -168,10 +168,14 @@ METHOD(pts_comp_evidence_t, get_validation, pts_comp_evid_validation_t, METHOD(pts_comp_evidence_t, set_validation, void, private_pts_comp_evidence_t *this, pts_comp_evid_validation_t validation, - chunk_t uri) + char *uri) { this->validation = validation; - this->policy_uri = chunk_clone(uri); + if (uri) + { + this->policy_uri = strdup(uri); + DBG3(DBG_PTS, "'%s'", uri); + } } METHOD(pts_comp_evidence_t, destroy, void, @@ -181,7 +185,7 @@ METHOD(pts_comp_evidence_t, destroy, void, free(this->measurement.ptr); free(this->pcr_before.ptr); free(this->pcr_after.ptr); - free(this->policy_uri.ptr); + free(this->policy_uri); free(this); } @@ -219,8 +223,8 @@ pts_comp_evidence_t *pts_comp_evidence_create(pts_comp_func_name_t *name, ); name->log(name, ""); - DBG2(DBG_PTS, "measurement time: %T", &measurement_time, FALSE); - DBG2(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement); + DBG3(DBG_PTS, "measurement time: %T", &measurement_time, FALSE); + DBG3(DBG_PTS, "PCR %2d extended with: %#B", extended_pcr, &measurement); return &this->public; } diff --git a/src/libpts/pts/components/pts_comp_evidence.h b/src/libpts/pts/components/pts_comp_evidence.h index fe86aa940..55776ce8b 100644 --- a/src/libpts/pts/components/pts_comp_evidence.h +++ b/src/libpts/pts/components/pts_comp_evidence.h @@ -120,7 +120,7 @@ struct pts_comp_evidence_t { * @return validation Validation Result */ pts_comp_evid_validation_t (*get_validation)(pts_comp_evidence_t *this, - chunk_t *uri); + char **uri); /** * Sets Validation Result if available @@ -129,7 +129,7 @@ struct pts_comp_evidence_t { * @param uri Verification Policy URI */ void (*set_validation)(pts_comp_evidence_t *this, - pts_comp_evid_validation_t validation, chunk_t uri); + pts_comp_evid_validation_t validation, char* uri); /** * Destroys a pts_comp_evidence_t object. diff --git a/src/libpts/pts/components/pts_comp_func_name.c b/src/libpts/pts/components/pts_comp_func_name.c index d98850d78..7501be044 100644 --- a/src/libpts/pts/components/pts_comp_func_name.c +++ b/src/libpts/pts/components/pts_comp_func_name.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * * HSR Hochschule fuer Technik Rapperswil * @@ -67,6 +67,12 @@ METHOD(pts_comp_func_name_t, get_qualifier, u_int8_t, return this->qualifier; } +METHOD(pts_comp_func_name_t, set_qualifier, void, + private_pts_comp_func_name_t *this, u_int8_t qualifier) +{ + this->qualifier = qualifier; +} + static bool equals(private_pts_comp_func_name_t *this, private_pts_comp_func_name_t *other) { @@ -137,6 +143,7 @@ pts_comp_func_name_t* pts_comp_func_name_create(u_int32_t vid, u_int32_t name, .get_vendor_id = _get_vendor_id, .get_name = _get_name, .get_qualifier = _get_qualifier, + .set_qualifier = _set_qualifier, .equals = (bool(*)(pts_comp_func_name_t*,pts_comp_func_name_t*))equals, .clone = _clone_, .log = _log_, diff --git a/src/libpts/pts/components/pts_comp_func_name.h b/src/libpts/pts/components/pts_comp_func_name.h index 2c7a84177..a3ffa1ba9 100644 --- a/src/libpts/pts/components/pts_comp_func_name.h +++ b/src/libpts/pts/components/pts_comp_func_name.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -54,6 +54,13 @@ struct pts_comp_func_name_t { */ u_int8_t (*get_qualifier)(pts_comp_func_name_t *this); + /** + * Set the PTS Component Functional Name Qualifier + * + * @param qualifier PTS Component Functional Name Qualifier to be set + */ + void (*set_qualifier)(pts_comp_func_name_t *this, u_int8_t qualifier); + /** * Check to PTS Component Functional Names for equality * diff --git a/src/libpts/pts/components/pts_component.h b/src/libpts/pts/components/pts_component.h index 524ff332d..da339a55f 100644 --- a/src/libpts/pts/components/pts_component.h +++ b/src/libpts/pts/components/pts_component.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ typedef struct pts_component_t pts_component_t; #include "pts/pts.h" #include "pts/pts_database.h" +#include "pts/pts_file_meas.h" #include "pts/components/pts_comp_func_name.h" #include "pts/components/pts_comp_evidence.h" @@ -59,30 +60,41 @@ struct pts_component_t { /** * Do evidence measurements on the PTS Functional Component * + * @param qualifier PTS Component Functional Name Qualifier * @param pts PTS interface * @param evidence returns component evidence measureemt + * @param measurements additional file measurements (NULL if not present) * @return status return code */ - status_t (*measure)(pts_component_t *this, pts_t *pts, + status_t (*measure)(pts_component_t *this, u_int8_t qualifier, pts_t *pts, pts_comp_evidence_t** evidence); /** * Verify the evidence measurements of the PTS Functional Component * + * @param qualifier PTS Component Functional Name Qualifier * @param pts PTS interface * @param evidence component evidence measurement to be verified * @return status return code */ - status_t (*verify)(pts_component_t *this, pts_t *pts, + status_t (*verify)(pts_component_t *this, u_int8_t qualifier, pts_t *pts, pts_comp_evidence_t *evidence); - /** * Tell the PTS Functional Component to finalize pending registrations + * and check for missing measurements + * + * @param qualifier PTS Component Functional Name Qualifier + * @return TRUE if finalization successful + */ + bool (*finalize)(pts_component_t *this, u_int8_t qualifier); + + /** + * Get a new reference to the PTS Functional Component * - * @return TRUE if there are pending registrations + * @return this, with an increased refcount */ - bool (*check_off_registrations)(pts_component_t *this); + pts_component_t* (*get_ref)(pts_component_t *this); /** * Destroys a pts_component_t object. diff --git a/src/libpts/pts/components/pts_component_manager.c b/src/libpts/pts/components/pts_component_manager.c index 8ac4767bf..e330aeebf 100644 --- a/src/libpts/pts/components/pts_component_manager.c +++ b/src/libpts/pts/components/pts_component_manager.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen - * + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -270,8 +269,7 @@ METHOD(pts_component_manager_t, create, pts_component_t*, { if (entry2->name == name->get_name(name) && entry2->create) { - component = entry2->create(name->get_qualifier(name), - depth, pts_db); + component = entry2->create(depth, pts_db); break; } } diff --git a/src/libpts/pts/components/pts_component_manager.h b/src/libpts/pts/components/pts_component_manager.h index 0079d0e26..61055ec74 100644 --- a/src/libpts/pts/components/pts_component_manager.h +++ b/src/libpts/pts/components/pts_component_manager.h @@ -30,8 +30,7 @@ typedef struct pts_component_manager_t pts_component_manager_t; #include #include -typedef pts_component_t* (*pts_component_create_t)(u_int8_t qualifier, - u_int32_t depth, +typedef pts_component_t* (*pts_component_create_t)(u_int32_t depth, pts_database_t *pts_db); /** diff --git a/src/libpts/pts/pts.c b/src/libpts/pts/pts.c index 65ae2b2d2..4c6c5bc22 100644 --- a/src/libpts/pts/pts.c +++ b/src/libpts/pts/pts.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -23,22 +23,13 @@ #include #include +#include #include #include +#include +#include #include -#define PTS_BUF_SIZE 4096 - -/** - * Maximum number of PCR's of TPM, TPM Spec 1.2 - */ -#define PCR_MAX_NUM 24 - -/** - * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2 - */ -#define PCR_LEN 20 - typedef struct private_pts_t private_pts_t; /** @@ -118,29 +109,9 @@ struct private_pts_t { certificate_t *aik; /** - * Table of extended PCRs with corresponding values - */ - u_char* pcrs[PCR_MAX_NUM]; - - /** - * Length of PCR registers - */ - size_t pcr_len; - - /** - * Number of extended PCR registers - */ - u_int32_t pcr_count; - - /** - * Highest extended PCR register - */ - u_int32_t pcr_max; - - /** - * Bitmap of extended PCR registers + * Shadow PCR set */ - u_int8_t pcr_select[PCR_MAX_NUM / 8]; + pts_pcr_t *pcrs; }; @@ -225,9 +196,13 @@ METHOD(pts_t, create_dh_nonce, bool, DBG2(DBG_PTS, "nonce length is %d", nonce_len); nonce = this->is_imc ? &this->responder_nonce : &this->initiator_nonce; chunk_free(nonce); - rng->allocate_bytes(rng, nonce_len, nonce); + if (!rng->allocate_bytes(rng, nonce_len, nonce)) + { + DBG1(DBG_PTS, "failed to allocate nonce"); + rng->destroy(rng); + return FALSE; + } rng->destroy(rng); - return TRUE; } @@ -282,10 +257,15 @@ METHOD(pts_t, calculate_secret, bool, hash_alg = pts_meas_algo_to_hash(this->dh_hash_algorithm); hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->allocate_hash(hasher, chunk_from_chars('1'), NULL); - hasher->allocate_hash(hasher, this->initiator_nonce, NULL); - hasher->allocate_hash(hasher, this->responder_nonce, NULL); - hasher->allocate_hash(hasher, shared_secret, &this->secret); + if (!hasher || + !hasher->get_hash(hasher, chunk_from_chars('1'), NULL) || + !hasher->get_hash(hasher, this->initiator_nonce, NULL) || + !hasher->get_hash(hasher, this->responder_nonce, NULL) || + !hasher->allocate_hash(hasher, shared_secret, &this->secret)) + { + DESTROY_IF(hasher); + return FALSE; + } hasher->destroy(hasher); /* The DH secret must be destroyed */ @@ -359,12 +339,6 @@ METHOD(pts_t, set_tpm_version_info, void, print_tpm_version_info(this); } -METHOD(pts_t, get_pcr_len, size_t, - private_pts_t *this) -{ - return this->pcr_len; -} - /** * Load an AIK Blob (TSS_TSPATTRIB_KEYBLOB_BLOB attribute) */ @@ -486,54 +460,6 @@ METHOD(pts_t, get_aik_keyid, bool, return success; } -METHOD(pts_t, hash_file, bool, - private_pts_t *this, hasher_t *hasher, char *pathname, u_char *hash) -{ - u_char buffer[PTS_BUF_SIZE]; - FILE *file; - int bytes_read; - - file = fopen(pathname, "rb"); - if (!file) - { - DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname, - strerror(errno)); - return FALSE; - } - while (TRUE) - { - bytes_read = fread(buffer, 1, sizeof(buffer), file); - if (bytes_read > 0) - { - hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL); - } - else - { - hasher->get_hash(hasher, chunk_empty, hash); - break; - } - } - fclose(file); - - return TRUE; -} - -/** - * Get the relative filename of a fully qualified file pathname - */ -static char* get_filename(char *pathname) -{ - char *pos, *filename; - - pos = filename = pathname; - while (pos && *(++pos) != '\0') - { - filename = pos; - pos = strchr(filename, '/'); - } - return filename; -} - METHOD(pts_t, is_path_valid, bool, private_pts_t *this, char *path, pts_error_code_t *error_code) { @@ -565,82 +491,6 @@ METHOD(pts_t, is_path_valid, bool, return TRUE; } -METHOD(pts_t, do_measurements, pts_file_meas_t*, - private_pts_t *this, u_int16_t request_id, char *pathname, bool is_directory) -{ - hasher_t *hasher; - hash_algorithm_t hash_alg; - u_char hash[HASH_SIZE_SHA384]; - chunk_t measurement; - pts_file_meas_t *measurements; - - /* Create a hasher */ - hash_alg = pts_meas_algo_to_hash(this->algorithm); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - if (!hasher) - { - DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); - return NULL; - } - - /* Create a measurement object */ - measurements = pts_file_meas_create(request_id); - - /* Link the hash to the measurement and set the measurement length */ - measurement = chunk_create(hash, hasher->get_hash_size(hasher)); - - if (is_directory) - { - enumerator_t *enumerator; - char *rel_name, *abs_name; - struct stat st; - - enumerator = enumerator_create_directory(pathname); - if (!enumerator) - { - DBG1(DBG_PTS," directory '%s' can not be opened, %s", pathname, - strerror(errno)); - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) - { - /* measure regular files only */ - if (S_ISREG(st.st_mode) && *rel_name != '.') - { - if (!hash_file(this, hasher, abs_name, hash)) - { - enumerator->destroy(enumerator); - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - DBG2(DBG_PTS, " %#B for '%s'", &measurement, rel_name); - measurements->add(measurements, rel_name, measurement); - } - } - enumerator->destroy(enumerator); - } - else - { - char *filename; - - if (!hash_file(this, hasher, pathname, hash)) - { - hasher->destroy(hasher); - measurements->destroy(measurements); - return NULL; - } - filename = get_filename(pathname); - DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); - measurements->add(measurements, filename, measurement); - } - hasher->destroy(hasher); - - return measurements; -} - /** * Obtain statistical information describing a file */ @@ -654,6 +504,7 @@ static bool file_metadata(char *pathname, pts_file_metadata_t **entry) if (stat(pathname, &st)) { DBG1(DBG_PTS, "unable to obtain statistics about '%s'", pathname); + free(this); return FALSE; } @@ -748,7 +599,7 @@ METHOD(pts_t, get_metadata, pts_file_meta_t*, metadata->destroy(metadata); return NULL; } - entry->filename = strdup(get_filename(pathname)); + entry->filename = strdup(basename(pathname)); metadata->add(metadata, entry); } @@ -809,7 +660,7 @@ METHOD(pts_t, extend_pcr, bool, TSS_HTPM hTPM; TSS_RESULT result; u_int32_t pcr_length; - chunk_t pcr_value; + chunk_t pcr_value = chunk_empty; result = Tspi_Context_Create(&hContext); if (result != TSS_SUCCESS) @@ -829,8 +680,8 @@ METHOD(pts_t, extend_pcr, bool, goto err; } - pcr_value = chunk_alloc(PCR_LEN); - result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PCR_LEN, input.ptr, + pcr_value = chunk_alloc(PTS_PCR_LEN); + result = Tspi_TPM_PcrExtend(hTPM, pcr_num, PTS_PCR_LEN, input.ptr, NULL, &pcr_length, &pcr_value.ptr); if (result != TSS_SUCCESS) { @@ -842,7 +693,7 @@ METHOD(pts_t, extend_pcr, bool, DBG3(DBG_PTS, "PCR %d extended with: %B", pcr_num, &input); DBG3(DBG_PTS, "PCR %d value after extend: %B", pcr_num, output); - + chunk_clear(&pcr_value); Tspi_Context_FreeMemory(hContext, NULL); Tspi_Context_Close(hContext); @@ -851,28 +702,12 @@ METHOD(pts_t, extend_pcr, bool, err: DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); - + chunk_clear(&pcr_value); Tspi_Context_FreeMemory(hContext, NULL); Tspi_Context_Close(hContext); - - return FALSE; -} - - -static void clear_pcrs(private_pts_t *this) -{ - int i; - for (i = 0; i <= this->pcr_max; i++) - { - free(this->pcrs[i]); - this->pcrs[i] = NULL; - } - this->pcr_count = 0; - this->pcr_max = 0; - - memset(this->pcr_select, 0x00, sizeof(this->pcr_select)); + return FALSE; } METHOD(pts_t, quote_tpm, bool, @@ -890,7 +725,8 @@ METHOD(pts_t, quote_tpm, bool, TSS_RESULT result; chunk_t quote_info; BYTE* versionInfo; - u_int32_t versionInfoSize, pcr, i = 0, f = 1; + u_int32_t versionInfoSize, pcr; + enumerator_t *enumerator; bool success = FALSE; result = Tspi_Context_Create(&hContext); @@ -943,32 +779,30 @@ METHOD(pts_t, quote_tpm, bool, Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, TSS_PCRS_STRUCT_INFO_SHORT, &hPcrComposite) : Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, - 0, &hPcrComposite); + TSS_PCRS_STRUCT_DEFAULT, &hPcrComposite); if (result != TSS_SUCCESS) { goto err2; } /* Select PCRs */ - for (pcr = 0; pcr <= this->pcr_max ; pcr++) - { - if (f == 256) + enumerator = this->pcrs->create_enumerator(this->pcrs); + while (enumerator->enumerate(enumerator, &pcr)) + { + result = use_quote2 ? + Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, + TSS_PCRS_DIRECTION_RELEASE) : + Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr); + if (result != TSS_SUCCESS) { - i++; - f = 1; - } - if (this->pcr_select[i] & f) - { - result = use_quote2 ? - Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, - TSS_PCRS_DIRECTION_RELEASE) : - Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr); - if (result != TSS_SUCCESS) - { - goto err3; - } + break; } - f <<= 1; + } + enumerator->destroy(enumerator); + + if (result != TSS_SUCCESS) + { + goto err3; } /* Set the Validation Data */ @@ -1028,87 +862,14 @@ err1: { DBG1(DBG_PTS, "TPM not available: tss error 0x%x", result); } - clear_pcrs(this); return success; } -METHOD(pts_t, select_pcr, bool, - private_pts_t *this, u_int32_t pcr) -{ - u_int32_t i, f; - - if (pcr >= PCR_MAX_NUM) - { - DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u", - pcr, PCR_MAX_NUM-1); - return FALSE; - } - - /* Determine PCR selection flag */ - i = pcr / 8; - f = 1 << (pcr - 8*i); - - /* Has this PCR already been selected? */ - if (!(this->pcr_select[i] & f)) - { - this->pcr_select[i] |= f; - this->pcr_max = max(this->pcr_max, pcr); - this->pcr_count++; - } - - return TRUE; -} - -METHOD(pts_t, add_pcr, bool, - private_pts_t *this, u_int32_t pcr, chunk_t pcr_before, chunk_t pcr_after) +METHOD(pts_t, get_pcrs, pts_pcr_t*, + private_pts_t *this) { - if (pcr >= PCR_MAX_NUM) - { - DBG1(DBG_PTS, "PCR %u: number is larger than maximum of %u", - pcr, PCR_MAX_NUM-1); - return FALSE; - } - - /* Is the length of the PCR registers already set? */ - if (this->pcr_len) - { - if (pcr_after.len != this->pcr_len) - { - DBG1(DBG_PTS, "PCR %02u: length is %d bytes but should be %d bytes", - pcr_after.len, this->pcr_len); - return FALSE; - } - } - else - { - this->pcr_len = pcr_after.len; - } - - /* Has the value of the PCR register already been assigned? */ - if (this->pcrs[pcr]) - { - if (!memeq(this->pcrs[pcr], pcr_before.ptr, this->pcr_len)) - { - DBG1(DBG_PTS, "PCR %02u: new pcr_before value does not equal " - "old pcr_after value"); - } - /* remove the old PCR value */ - free(this->pcrs[pcr]); - } - else - { - /* add extended PCR Register */ - this->pcr_select[pcr / 8] |= 1 << (pcr % 8); - this->pcr_max = max(this->pcr_max, pcr); - this->pcr_count++; - } - - /* Duplicate and store current PCR value */ - pcr_after = chunk_clone(pcr_after); - this->pcrs[pcr] = pcr_after.ptr; - - return TRUE; + return this->pcrs; } /** @@ -1130,13 +891,11 @@ METHOD(pts_t, get_quote_info, bool, pts_meas_algorithms_t comp_hash_algo, chunk_t *out_pcr_comp, chunk_t *out_quote_info) { - u_int8_t size_of_select; - int pcr_comp_len, i; - chunk_t pcr_comp, hash_pcr_comp; + chunk_t selection, pcr_comp, hash_pcr_comp; bio_writer_t *writer; hasher_t *hasher; - if (this->pcr_count == 0) + if (!this->pcrs->get_count(this->pcrs)) { DBG1(DBG_PTS, "No extended PCR entries available, " "unable to construct TPM Quote Info"); @@ -1154,34 +913,9 @@ METHOD(pts_t, get_quote_info, bool, "unable to construct TPM Quote Info2"); return FALSE; } - - /** - * A TPM v1.2 has 24 PCR Registers - * so the bitmask field length used by TrouSerS is at least 3 bytes - */ - size_of_select = max(PCR_MAX_NUM / 8, 1 + this->pcr_max / 8); - pcr_comp_len = 2 + size_of_select + 4 + this->pcr_count * this->pcr_len; - - writer = bio_writer_create(pcr_comp_len); - - writer->write_uint16(writer, size_of_select); - for (i = 0; i < size_of_select; i++) - { - writer->write_uint8(writer, this->pcr_select[i]); - } - writer->write_uint32(writer, this->pcr_count * this->pcr_len); - for (i = 0; i < 8 * size_of_select; i++) - { - if (this->pcrs[i]) - { - writer->write_data(writer, chunk_create(this->pcrs[i], this->pcr_len)); - } - } - pcr_comp = chunk_clone(writer->get_buf(writer)); - DBG3(DBG_PTS, "constructed PCR Composite: %B", &pcr_comp); + pcr_comp = this->pcrs->get_composite(this->pcrs); - writer->destroy(writer); /* Output the TPM_PCR_COMPOSITE expected from IMC */ if (comp_hash_algo) @@ -1192,7 +926,12 @@ METHOD(pts_t, get_quote_info, bool, hasher = lib->crypto->create_hasher(lib->crypto, algo); /* Hash the PCR Composite Structure */ - hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp); + if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, out_pcr_comp)) + { + DESTROY_IF(hasher); + free(pcr_comp.ptr); + return FALSE; + } DBG3(DBG_PTS, "constructed PCR Composite hash: %#B", out_pcr_comp); hasher->destroy(hasher); } @@ -1203,7 +942,13 @@ METHOD(pts_t, get_quote_info, bool, /* SHA1 hash of PCR Composite to construct TPM_QUOTE_INFO */ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp); + if (!hasher || !hasher->allocate_hash(hasher, pcr_comp, &hash_pcr_comp)) + { + DESTROY_IF(hasher); + chunk_free(out_pcr_comp); + free(pcr_comp.ptr); + return FALSE; + } hasher->destroy(hasher); /* Construct TPM_QUOTE_INFO/TPM_QUOTE_INFO2 structure */ @@ -1220,15 +965,11 @@ METHOD(pts_t, get_quote_info, bool, /* Secret assessment value 20 bytes (nonce) */ writer->write_data(writer, this->secret); - /* Length of the PCR selection field */ - writer->write_uint16(writer, size_of_select); - /* PCR selection */ - for (i = 0; i < size_of_select ; i++) - { - writer->write_uint8(writer, this->pcr_select[i]); - } - + selection.ptr = pcr_comp.ptr; + selection.len = 2 + this->pcrs->get_selection_size(this->pcrs); + writer->write_data(writer, selection); + /* TPM Locality Selection */ writer->write_uint8(writer, TPM_LOC_ZERO); @@ -1263,7 +1004,6 @@ METHOD(pts_t, get_quote_info, bool, writer->destroy(writer); free(pcr_comp.ptr); free(hash_pcr_comp.ptr); - clear_pcrs(this); return TRUE; } @@ -1295,7 +1035,7 @@ METHOD(pts_t, verify_quote_signature, bool, METHOD(pts_t, destroy, void, private_pts_t *this) { - clear_pcrs(this); + DESTROY_IF(this->pcrs); DESTROY_IF(this->aik); DESTROY_IF(this->dh); free(this->initiator_nonce.ptr); @@ -1357,7 +1097,7 @@ static char* extract_platform_info(void) { strcpy(buf, str_debian); pos += strlen(str_debian); - len -= strlen(str_debian); + len -= strlen(str_debian); } fseek(file, 0, SEEK_END); @@ -1477,6 +1217,14 @@ static bool has_tpm(private_pts_t *this) pts_t *pts_create(bool is_imc) { private_pts_t *this; + pts_pcr_t *pcrs; + + pcrs = pts_pcr_create(); + if (!pcrs) + { + DBG1(DBG_PTS, "shadow PCR set could not be created"); + return NULL; + } INIT(this, .public = { @@ -1494,19 +1242,15 @@ pts_t *pts_create(bool is_imc) .set_platform_info = _set_platform_info, .get_tpm_version_info = _get_tpm_version_info, .set_tpm_version_info = _set_tpm_version_info, - .get_pcr_len = _get_pcr_len, .get_aik = _get_aik, .set_aik = _set_aik, .get_aik_keyid = _get_aik_keyid, .is_path_valid = _is_path_valid, - .hash_file = _hash_file, - .do_measurements = _do_measurements, .get_metadata = _get_metadata, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote_tpm = _quote_tpm, - .select_pcr = _select_pcr, - .add_pcr = _add_pcr, + .get_pcrs = _get_pcrs, .get_quote_info = _get_quote_info, .verify_quote_signature = _verify_quote_signature, .destroy = _destroy, @@ -1515,6 +1259,7 @@ pts_t *pts_create(bool is_imc) .proto_caps = PTS_PROTO_CAPS_V, .algorithm = PTS_MEAS_ALGO_SHA256, .dh_hash_algorithm = PTS_MEAS_ALGO_SHA256, + .pcrs = pcrs, ); if (is_imc) @@ -1524,7 +1269,6 @@ pts_t *pts_create(bool is_imc) if (has_tpm(this)) { this->has_tpm = TRUE; - this->pcr_len = PCR_LEN; this->proto_caps |= PTS_PROTO_CAPS_T | PTS_PROTO_CAPS_D; load_aik(this); load_aik_blob(this); diff --git a/src/libpts/pts/pts.h b/src/libpts/pts/pts.h index 212acb02a..5f88cd15c 100644 --- a/src/libpts/pts/pts.h +++ b/src/libpts/pts/pts.h @@ -29,6 +29,7 @@ typedef struct pts_t pts_t; #include "pts_file_meas.h" #include "pts_file_meta.h" #include "pts_dh_group.h" +#include "pts_pcr.h" #include "pts_req_func_comp_evid.h" #include "pts_simple_evid_final.h" #include "components/pts_comp_func_name.h" @@ -189,13 +190,6 @@ struct pts_t { */ void (*set_tpm_version_info)(pts_t *this, chunk_t info); - /** - * Get the length of the TPM PCR registers - * - * @return Length of PCR registers in bytes, 0 if undefined - */ - size_t (*get_pcr_len)(pts_t *this); - /** * Get Attestation Identity Certificate or Public Key * @@ -229,35 +223,14 @@ struct pts_t { */ bool (*is_path_valid)(pts_t *this, char *path, pts_error_code_t *error_code); - /** - * Compute a hash over a file - * @param hasher Hasher to be used - * @param pathname Absolute path of a file - * @param hash Buffer to keep hash output - * @return TRUE if path is valid and hashing succeeded - */ - bool (*hash_file)(pts_t *this, hasher_t *hasher, char *pathname, u_char *hash); - - /** - * Do PTS File Measurements - * - * @param request_id ID of PTS File Measurement Request - * @param pathname Absolute pathname of file to be measured - * @param is_directory TRUE if directory contents are measured - * @return PTS File Measurements of NULL if FAILED - */ - pts_file_meas_t* (*do_measurements)(pts_t *this, u_int16_t request_id, - char *pathname, bool is_directory); - /** * Obtain file metadata * * @param pathname Absolute pathname of file/directory - * @param is_directory TRUE if directory contents are requested + * @param is_dir TRUE if directory contents are requested * @return PTS File Metadata or NULL if FAILED */ - pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, - bool is_directory); + pts_file_meta_t* (*get_metadata)(pts_t *this, char *pathname, bool is_dir); /** * Reads given PCR value and returns it @@ -294,24 +267,12 @@ struct pts_t { bool (*quote_tpm)(pts_t *this, bool use_quote2, chunk_t *pcr_comp, chunk_t *quote_sig); - /** - * Mark an extended PCR as selected - * - * @param pcr Number of the extended PCR - * @return TRUE if PCR number is valid - */ - bool (*select_pcr)(pts_t *this, u_int32_t pcr); - - /** - * Add an extended PCR with its corresponding value + /** + * Get the shadow PCR set * - * @param pcr Number of the extended PCR - * @param pcr_before PCR value before extension - * @param pcr_after PCR value after extension - * @return TRUE if PCR number and register length is valid + * @return shadow PCR set */ - bool (*add_pcr)(pts_t *this, u_int32_t pcr, chunk_t pcr_before, - chunk_t pcr_after); + pts_pcr_t* (*get_pcrs)(pts_t *this); /** * Constructs and returns TPM Quote Info structure expected from IMC diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index 282755c0a..946f37e1e 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -121,6 +121,42 @@ METHOD(pts_database_t, check_aik_keyid, status_t, return SUCCESS; } +METHOD(pts_database_t, check_file_measurement, status_t, + private_pts_database_t *this, char *product, pts_meas_algorithms_t algo, + chunk_t measurement, char *filename) +{ + enumerator_t *e; + chunk_t hash; + status_t status = NOT_FOUND; + + e = this->db->query(this->db, + "SELECT fh.hash FROM file_hashes AS fh " + "JOIN files AS f ON f.id = fh.file " + "JOIN products AS p ON p.id = fh.product " + "WHERE p.name = ? AND f.path = ? AND fh.algo = ?", + DB_TEXT, product, DB_TEXT, filename, DB_INT, algo, DB_BLOB); + if (!e) + { + return FAILED; + } + while (e->enumerate(e, &hash)) + { + /* with relative filenames there might be multiple entries */ + if (chunk_equals(measurement, hash)) + { + status = SUCCESS; + break; + } + else + { + status = VERIFY_ERROR; + } + } + e->destroy(e); + + return status; +} + METHOD(pts_database_t, create_comp_evid_enumerator, enumerator_t*, private_pts_database_t *this, int kid) { @@ -169,7 +205,7 @@ METHOD(pts_database_t, check_comp_measurement, status_t, "found in database", pcr, seq_no); DBG1(DBG_PTS, " expected: %#B", &hash); DBG1(DBG_PTS, " received: %#B", &measurement); - status = FAILED; + status = VERIFY_ERROR; break; } } @@ -290,6 +326,7 @@ pts_database_t *pts_database_create(char *uri) .create_comp_evid_enumerator = _create_comp_evid_enumerator, .create_file_hash_enumerator = _create_file_hash_enumerator, .check_aik_keyid = _check_aik_keyid, + .check_file_measurement = _check_file_measurement, .check_comp_measurement = _check_comp_measurement, .insert_comp_measurement = _insert_comp_measurement, .delete_comp_measurements = _delete_comp_measurements, diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index a9a68ac76..649ef0e31 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -81,6 +81,19 @@ struct pts_database_t { */ enumerator_t* (*create_comp_evid_enumerator)(pts_database_t *this, int kid); + /** + * Check PTS file measurement against reference stored in database + * + * @param product Software product (os, vpn client, etc.) + * @param algo File measurement hash algorithm used + * @param measurement File measurement hash + * @param filename Optional name of the file to be checked + * @return Status + */ + status_t (*check_file_measurement)(pts_database_t *this, char *product, + pts_meas_algorithms_t algo, + chunk_t measurement, char *filename); + /** * Check a functional component measurement against value stored in database * diff --git a/src/libpts/pts/pts_error.c b/src/libpts/pts/pts_error.c index 6e914b2a9..1e79689f9 100644 --- a/src/libpts/pts/pts_error.c +++ b/src/libpts/pts/pts_error.c @@ -46,13 +46,13 @@ pa_tnc_attr_t* pts_hash_alg_error_create(pts_meas_algorithms_t algorithms) bio_writer_t *writer; chunk_t msg_info; pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_HASH_ALG_NOT_SUPPORTED }; writer = bio_writer_create(4); writer->write_uint16(writer, 0x0000); writer->write_uint16(writer, algorithms); msg_info = writer->get_buf(writer); - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_HASH_ALG_NOT_SUPPORTED, - msg_info); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); writer->destroy(writer); return attr; @@ -66,13 +66,13 @@ pa_tnc_attr_t* pts_dh_group_error_create(pts_dh_group_t dh_groups) bio_writer_t *writer; chunk_t msg_info; pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED }; writer = bio_writer_create(4); writer->write_uint16(writer, 0x0000); writer->write_uint16(writer, dh_groups); msg_info = writer->get_buf(writer); - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_DH_GRPS_NOT_SUPPORTED, - msg_info); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); writer->destroy(writer); return attr; @@ -86,13 +86,13 @@ pa_tnc_attr_t* pts_dh_nonce_error_create(int min_nonce_len, int max_nonce_len) bio_writer_t *writer; chunk_t msg_info; pa_tnc_attr_t *attr; + pen_type_t error_code = { PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH }; writer = bio_writer_create(4); writer->write_uint16(writer, min_nonce_len); writer->write_uint16(writer, max_nonce_len); msg_info = writer->get_buf(writer); - attr = ietf_attr_pa_tnc_error_create(PEN_TCG, TCG_PTS_BAD_NONCE_LENGTH, - msg_info); + attr = ietf_attr_pa_tnc_error_create(error_code, msg_info); writer->destroy(writer); return attr; diff --git a/src/libpts/pts/pts_file_meas.c b/src/libpts/pts/pts_file_meas.c index f0e0d4c0a..4fece6b3c 100644 --- a/src/libpts/pts/pts_file_meas.c +++ b/src/libpts/pts/pts_file_meas.c @@ -18,6 +18,10 @@ #include #include +#include +#include +#include + typedef struct private_pts_file_meas_t private_pts_file_meas_t; /** @@ -107,6 +111,51 @@ METHOD(pts_file_meas_t, create_enumerator, enumerator_t*, (void*)entry_filter, NULL, NULL); } +METHOD(pts_file_meas_t, check, bool, + private_pts_file_meas_t *this, pts_database_t *pts_db, char *product, + pts_meas_algorithms_t algo) +{ + enumerator_t *enumerator; + entry_t *entry; + int count_ok = 0, count_not_found = 0, count_differ = 0; + status_t status; + + enumerator = this->list->create_enumerator(this->list); + while (enumerator->enumerate(enumerator, &entry)) + { + status = pts_db->check_file_measurement(pts_db, product, algo, + entry->measurement, entry->filename); + switch (status) + { + case SUCCESS: + DBG3(DBG_PTS, " %#B for '%s' is ok", &entry->measurement, + entry->filename); + count_ok++; + break; + case NOT_FOUND: + DBG2(DBG_PTS, " %#B for '%s' not found", &entry->measurement, + entry->filename); + count_not_found++; + break; + case VERIFY_ERROR: + DBG1(DBG_PTS, " %#B for '%s' differs", &entry->measurement, + entry->filename); + count_differ++; + break; + case FAILED: + default: + DBG1(DBG_PTS, " %#B for '%s' failed", &entry->measurement, + entry->filename); + } + } + enumerator->destroy(enumerator); + + DBG1(DBG_PTS, "%d measurements, %d ok, %d not found, %d differ", + this->list->get_count(this->list), + count_ok, count_not_found, count_differ); + return TRUE; +} + METHOD(pts_file_meas_t, verify, bool, private_pts_file_meas_t *this, enumerator_t *e_hash, bool is_dir) { @@ -174,6 +223,7 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id) .get_file_count = _get_file_count, .add = _add, .create_enumerator = _create_enumerator, + .check = _check, .verify = _verify, .destroy = _destroy, }, @@ -184,3 +234,141 @@ pts_file_meas_t *pts_file_meas_create(u_int16_t request_id) return &this->public; } +/** + * Hash a file with a given absolute pathname + */ +static bool hash_file(hasher_t *hasher, char *pathname, u_char *hash) +{ + u_char buffer[4096]; + size_t bytes_read; + bool success = TRUE; + FILE *file; + + file = fopen(pathname, "rb"); + if (!file) + { + DBG1(DBG_PTS," file '%s' can not be opened, %s", pathname, + strerror(errno)); + return FALSE; + } + while (TRUE) + { + bytes_read = fread(buffer, 1, sizeof(buffer), file); + if (bytes_read > 0) + { + if (!hasher->get_hash(hasher, chunk_create(buffer, bytes_read), NULL)) + { + DBG1(DBG_PTS, " hasher increment error"); + success = FALSE; + break; + } + } + else + { + if (!hasher->get_hash(hasher, chunk_empty, hash)) + { + DBG1(DBG_PTS, " hasher finalize error"); + success = FALSE; + } + break; + } + } + fclose(file); + + return success; +} + +/** + * See header + */ +pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id, + char *pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg) +{ + private_pts_file_meas_t *this; + hash_algorithm_t hash_alg; + hasher_t *hasher; + u_char hash[HASH_SIZE_SHA384]; + chunk_t measurement; + char* filename; + bool success = TRUE; + + /* Create a hasher and a hash measurement buffer */ + hash_alg = pts_meas_algo_to_hash(alg); + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher) + { + DBG1(DBG_PTS, "hasher %N not available", hash_algorithm_names, hash_alg); + return NULL; + } + measurement = chunk_create(hash, hasher->get_hash_size(hasher)); + + INIT(this, + .public = { + .get_request_id = _get_request_id, + .get_file_count = _get_file_count, + .add = _add, + .create_enumerator = _create_enumerator, + .check = _check, + .verify = _verify, + .destroy = _destroy, + }, + .request_id = request_id, + .list = linked_list_create(), + ); + + if (is_dir) + { + enumerator_t *enumerator; + char *rel_name, *abs_name; + struct stat st; + + enumerator = enumerator_create_directory(pathname); + if (!enumerator) + { + DBG1(DBG_PTS, " directory '%s' can not be opened, %s", pathname, + strerror(errno)); + success = FALSE; + goto end; + } + while (enumerator->enumerate(enumerator, &rel_name, &abs_name, &st)) + { + /* measure regular files only */ + if (S_ISREG(st.st_mode) && *rel_name != '.') + { + if (!hash_file(hasher, abs_name, hash)) + { + success = FALSE; + break; + } + filename = use_rel_name ? rel_name : abs_name; + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + } + } + enumerator->destroy(enumerator); + } + else + { + if (!hash_file(hasher, pathname, hash)) + { + success = FALSE; + goto end; + } + filename = use_rel_name ? basename(pathname) : pathname; + DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); + add(this, filename, measurement); + } + +end: + hasher->destroy(hasher); + if (success) + { + return &this->public; + } + else + { + destroy(this); + return NULL; + } +} diff --git a/src/libpts/pts/pts_file_meas.h b/src/libpts/pts/pts_file_meas.h index 3ebb5c2a0..71efd5026 100644 --- a/src/libpts/pts/pts_file_meas.h +++ b/src/libpts/pts/pts_file_meas.h @@ -21,6 +21,8 @@ #ifndef PTS_FILE_MEAS_H_ #define PTS_FILE_MEAS_H_ +#include "pts/pts_database.h" + #include typedef struct pts_file_meas_t pts_file_meas_t; @@ -59,6 +61,17 @@ struct pts_file_meas_t { */ enumerator_t* (*create_enumerator)(pts_file_meas_t *this); + /** + * Check PTS File Measurements against reference value in the database + * + * @param db PTS Measurement database + * @param product Software product (os, vpn client, etc.) + * @param algo PTS Measurement algorithm used + * @return TRUE if all measurements agreed + */ + bool (*check)(pts_file_meas_t *this, pts_database_t *db, char* product, + pts_meas_algorithms_t algo); + /** * Verify stored hashes against PTS File Measurements * @@ -82,4 +95,17 @@ struct pts_file_meas_t { */ pts_file_meas_t* pts_file_meas_create(u_int16_t request_id); +/** + * Creates a pts_file_meas_t object measuring a file/directory + * + * @param request_id ID of PTS File Measurement Request + * @param pathname Absolute file or directory pathname + * @param is_dir TRUE if directory path + * @param use_rel_name TRUE if relative filenames are to be used + * @param alg PTS hash measurement algorithm to be used + */ +pts_file_meas_t* pts_file_meas_create_from_path(u_int16_t request_id, + char* pathname, bool is_dir, bool use_rel_name, + pts_meas_algorithms_t alg); + #endif /** PTS_FILE_MEAS_H_ @}*/ diff --git a/src/libpts/pts/pts_meas_algo.c b/src/libpts/pts/pts_meas_algo.c index 865857d3c..fbc9c6959 100644 --- a/src/libpts/pts/pts_meas_algo.c +++ b/src/libpts/pts/pts_meas_algo.c @@ -17,12 +17,21 @@ #include -ENUM(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_SHA384, - "None", - "SHA1", - "SHA256", - "SHA384" -); +ENUM_BEGIN(pts_meas_algorithm_names, PTS_MEAS_ALGO_NONE, PTS_MEAS_ALGO_NONE, + "None"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA384, PTS_MEAS_ALGO_SHA384, + PTS_MEAS_ALGO_NONE, + "SHA384"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA256, PTS_MEAS_ALGO_SHA256, + PTS_MEAS_ALGO_SHA384, + "SHA256"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1, PTS_MEAS_ALGO_SHA1, + PTS_MEAS_ALGO_SHA256, + "SHA1"); +ENUM_NEXT(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA, PTS_MEAS_ALGO_SHA1_IMA, + PTS_MEAS_ALGO_SHA1, + "SHA1-IMA"); +ENUM_END(pts_meas_algorithm_names, PTS_MEAS_ALGO_SHA1_IMA); /** * Described in header. diff --git a/src/libpts/pts/pts_meas_algo.h b/src/libpts/pts/pts_meas_algo.h index 1d96a4946..27cdaea7e 100644 --- a/src/libpts/pts/pts_meas_algo.h +++ b/src/libpts/pts/pts_meas_algo.h @@ -30,10 +30,11 @@ typedef enum pts_meas_algorithms_t pts_meas_algorithms_t; * PTS Measurement Algorithms */ enum pts_meas_algorithms_t { - PTS_MEAS_ALGO_NONE = 0, - PTS_MEAS_ALGO_SHA1 = (1<<15), - PTS_MEAS_ALGO_SHA256 = (1<<14), - PTS_MEAS_ALGO_SHA384 = (1<<13), + PTS_MEAS_ALGO_NONE = 0, + PTS_MEAS_ALGO_SHA384 = (1<<13), + PTS_MEAS_ALGO_SHA256 = (1<<14), + PTS_MEAS_ALGO_SHA1 = (1<<15), + PTS_MEAS_ALGO_SHA1_IMA = (1<<16), /* internal use only */ }; /** diff --git a/src/libpts/pts/pts_pcr.c b/src/libpts/pts/pts_pcr.c new file mode 100644 index 000000000..a7a2f5fae --- /dev/null +++ b/src/libpts/pts/pts_pcr.c @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pts_pcr.h" + +#include + +#include + +typedef struct private_pts_pcr_t private_pts_pcr_t; + +/** + * Private data of a pts_pcr_t object. + * + */ +struct private_pts_pcr_t { + + /** + * Public pts_pcr_t interface. + */ + pts_pcr_t public; + + /** + * Shadow PCR registers + */ + chunk_t pcrs[PTS_PCR_MAX_NUM]; + + /** + * Number of extended PCR registers + */ + u_int32_t pcr_count; + + /** + * Highest extended PCR register + */ + u_int32_t pcr_max; + + /** + * Bitmap of extended PCR registers + */ + u_int8_t pcr_select[PTS_PCR_MAX_NUM / 8]; + + /** + * Hasher used to extend shadow PCRs + */ + hasher_t *hasher; + +}; + +METHOD(pts_pcr_t, get_count, u_int32_t, + private_pts_pcr_t *this) +{ + return this->pcr_count; +} + +METHOD(pts_pcr_t, select_pcr, bool, + private_pts_pcr_t *this, u_int32_t pcr) +{ + u_int32_t i, f; + + if (pcr >= PTS_PCR_MAX_NUM) + { + DBG1(DBG_PTS, "PCR %2u: number is larger than maximum of %u", + pcr, PTS_PCR_MAX_NUM-1); + return FALSE; + } + + /* Determine PCR selection flag */ + i = pcr / 8; + f = 1 << (pcr - 8*i); + + /* Has this PCR already been selected? */ + if (!(this->pcr_select[i] & f)) + { + this->pcr_select[i] |= f; + this->pcr_max = max(this->pcr_max, pcr); + this->pcr_count++; + } + return TRUE; +} + +METHOD(pts_pcr_t, get_selection_size, size_t, + private_pts_pcr_t *this) +{ + + /** + * A TPM v1.2 has 24 PCR Registers so the bitmask field length + * used by TrouSerS is at least 3 bytes + */ + return PTS_PCR_MAX_NUM / 8; +} + +typedef struct { + /** implements enumerator_t */ + enumerator_t public; + /** current PCR */ + u_int32_t pcr; + /** back reference to parent */ + private_pts_pcr_t *pcrs; +} pcr_enumerator_t; + +/** + * Implementation of enumerator.enumerate + */ +static bool pcr_enumerator_enumerate(pcr_enumerator_t *this, ...) +{ + u_int32_t *pcr, i, f; + va_list args; + + va_start(args, this); + pcr = va_arg(args, u_int32_t*); + va_end(args); + + while (this->pcr <= this->pcrs->pcr_max) + { + /* Determine PCR selection flag */ + i = this->pcr / 8; + f = 1 << (this->pcr - 8*i); + + /* Assign current PCR to output argument and increase */ + *pcr = this->pcr++; + + /* return if PCR is selected */ + if (this->pcrs->pcr_select[i] & f) + { + return TRUE; + } + } + return FALSE; +} + +METHOD(pts_pcr_t, create_enumerator, enumerator_t*, + private_pts_pcr_t *this) +{ + pcr_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = (void*)pcr_enumerator_enumerate, + .destroy = (void*)free, + }, + .pcrs = this, + ); + + return (enumerator_t*)enumerator; +} + +METHOD(pts_pcr_t, get, chunk_t, + private_pts_pcr_t *this, u_int32_t pcr) +{ + return (pcr < PTS_PCR_MAX_NUM) ? this->pcrs[pcr] : chunk_empty; +} + +METHOD(pts_pcr_t, set, bool, + private_pts_pcr_t *this, u_int32_t pcr, chunk_t value) +{ + if (value.len != PTS_PCR_LEN) + { + DBG1(DBG_PTS, "PCR %2u: value does not fit", pcr); + return FALSE; + } + if (select_pcr(this, pcr)) + { + memcpy(this->pcrs[pcr].ptr, value.ptr, PTS_PCR_LEN); + return TRUE; + } + return FALSE; +} + +METHOD(pts_pcr_t, extend, chunk_t, + private_pts_pcr_t *this, u_int32_t pcr, chunk_t measurement) +{ + if (measurement.len != PTS_PCR_LEN) + { + DBG1(DBG_PTS, "PCR %2u: measurement does not fit", pcr); + return chunk_empty; + } + if (!select_pcr(this, pcr)) + { + return chunk_empty; + } + if (!this->hasher->get_hash(this->hasher, this->pcrs[pcr] , NULL) || + !this->hasher->get_hash(this->hasher, measurement, this->pcrs[pcr].ptr)) + { + DBG1(DBG_PTS, "PCR %2u: not extended due to hasher problem", pcr); + return chunk_empty; + } + return this->pcrs[pcr]; +} + +METHOD(pts_pcr_t, get_composite, chunk_t, + private_pts_pcr_t *this) +{ + chunk_t composite; + enumerator_t *enumerator; + u_int16_t selection_size; + u_int32_t pcr_field_size, pcr; + u_char *pos; + + selection_size = get_selection_size(this); + pcr_field_size = this->pcr_count * PTS_PCR_LEN; + + composite = chunk_alloc(2 + selection_size + 4 + pcr_field_size); + pos = composite.ptr; + htoun16(pos, selection_size); + pos += 2; + memcpy(pos, this->pcr_select, selection_size); + pos += selection_size; + htoun32(pos, pcr_field_size); + pos += 4; + + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &pcr)) + { + memcpy(pos, this->pcrs[pcr].ptr, PTS_PCR_LEN); + pos += PTS_PCR_LEN; + } + enumerator->destroy(enumerator); + + DBG3(DBG_PTS, "constructed PCR Composite: %B", &composite); + return composite; +} + +METHOD(pts_pcr_t, destroy, void, + private_pts_pcr_t *this) +{ + u_int32_t i; + + for (i = 0; i < PTS_PCR_MAX_NUM; i++) + { + free(this->pcrs[i].ptr); + } + this->hasher->destroy(this->hasher); + free(this); +} + +/** + * See header + */ +pts_pcr_t *pts_pcr_create(void) +{ + private_pts_pcr_t *this; + hasher_t *hasher; + u_int32_t i; + + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) + { + DBG1(DBG_PTS, "%N hasher could not be created", + hash_algorithm_short_names, HASH_SHA1); + return NULL; + } + + INIT(this, + .public = { + .get_count = _get_count, + .select_pcr = _select_pcr, + .get_selection_size = _get_selection_size, + .create_enumerator = _create_enumerator, + .get = _get, + .set = _set, + .extend = _extend, + .get_composite = _get_composite, + .destroy = _destroy, + }, + .hasher = hasher, + ); + + for (i = 0; i < PTS_PCR_MAX_NUM; i++) + { + this->pcrs[i] = chunk_alloc(PTS_PCR_LEN); + memset(this->pcrs[i].ptr, 0x00, PTS_PCR_LEN); + } + + return &this->public; +} + diff --git a/src/libpts/pts/pts_pcr.h b/src/libpts/pts/pts_pcr.h new file mode 100644 index 000000000..f638b5ee4 --- /dev/null +++ b/src/libpts/pts/pts_pcr.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2012 Andreas Steffen + * HSR Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pts_pcr pts_pcr + * @{ @ingroup pts + */ + +#ifndef PTS_PCR_H_ +#define PTS_PCR_H_ + +typedef struct pts_pcr_t pts_pcr_t; + +#include + +/** + * Maximum number of PCR's of TPM, TPM Spec 1.2 + */ +#define PTS_PCR_MAX_NUM 24 + +/** + * Number of bytes that can be saved in a PCR of TPM, TPM Spec 1.2 + */ +#define PTS_PCR_LEN 20 + +/** + * Class implementing a shadow PCR register set + */ +struct pts_pcr_t { + + /** + * Get the number of selected PCRs + * + * @return number of selected PCRs + */ + u_int32_t (*get_count)(pts_pcr_t *this); + + /** + * Mark a PCR as selected + * + * @param pcr index of PCR + * @return TRUE if PCR index exists + */ + bool (*select_pcr)(pts_pcr_t *this, u_int32_t pcr); + + /** + * Get the size of the selection field in bytes + * + * @return number of bytes written + */ + size_t (*get_selection_size)(pts_pcr_t *this); + + /** + * Create an enumerator over all selected PCR indexes + * + * @return enumerator + */ + enumerator_t* (*create_enumerator)(pts_pcr_t *this); + + /** + * Get the current content of a PCR + * + * @param pcr index of PCR + * @return content of PCR + */ + chunk_t (*get)(pts_pcr_t *this, u_int32_t pcr); + + /** + * Set the content of a PCR + * + * @param pcr index of PCR + * @param value new value of PCR + * @return TRUE if value could be set + */ + bool (*set)(pts_pcr_t *this, u_int32_t pcr, chunk_t value); + + /** + * Extend the content of a PCR + * + * @param pcr index of PCR + * @param measurement measurment value to be extended into PCR + * @return new content of PCR + */ + chunk_t (*extend)(pts_pcr_t *this, u_int32_t pcr, chunk_t measurement); + + /** + * Create a PCR Composite object over all selected PCRs + * + * @return PCR Composite object (must be freed) + */ + chunk_t (*get_composite)(pts_pcr_t *this); + + /** + + * Destroys a pts_pcr_t object. + */ + void (*destroy)(pts_pcr_t *this); + +}; + +/** + * Creates an pts_pcr_t object + */ +pts_pcr_t* pts_pcr_create(void); + +#endif /** PTS_PCR_H_ @}*/ diff --git a/src/libpts/tcg/tcg_pts_attr_aik.c b/src/libpts/tcg/tcg_pts_attr_aik.c index 9be3794b6..75f3f179c 100644 --- a/src/libpts/tcg/tcg_pts_attr_aik.c +++ b/src/libpts/tcg/tcg_pts_attr_aik.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -49,14 +49,9 @@ struct private_tcg_pts_attr_aik_t { tcg_pts_attr_aik_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -79,13 +74,7 @@ struct private_tcg_pts_attr_aik_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_aik_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_aik_t *this) { return this->type; @@ -117,6 +106,10 @@ METHOD(pa_tnc_attr_t, build, void, cred_encoding_type_t encoding_type = CERT_ASN1_DER; chunk_t aik_blob; + if (this->value.ptr) + { + return; + } if (this->aik->get_type(this->aik) == CERT_TRUSTED_PUBKEY) { flags |= PTS_AIK_FLAGS_NAKED_KEY; @@ -202,7 +195,6 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -214,8 +206,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create(certificate_t *aik) }, .get_aik = _get_aik, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_AIK, + .type = { PEN_TCG, TCG_PTS_AIK }, .aik = aik->get_ref(aik), .ref = 1, ); @@ -234,7 +225,6 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -246,8 +236,7 @@ pa_tnc_attr_t *tcg_pts_attr_aik_create_from_data(chunk_t data) }, .get_aik = _get_aik, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_AIK, + .type = { PEN_TCG, TCG_PTS_AIK }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c index dce98e87d..3ca255cba 100644 --- a/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_finish.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -53,14 +53,9 @@ struct private_tcg_pts_attr_dh_nonce_finish_t { tcg_pts_attr_dh_nonce_finish_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -93,13 +88,7 @@ struct private_tcg_pts_attr_dh_nonce_finish_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_dh_nonce_finish_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_dh_nonce_finish_t *this) { return this->type; @@ -128,6 +117,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_DH_NONCE_FINISH_SIZE); writer->write_uint8 (writer, PTS_DH_NONCE_FINISH_RESERVED); writer->write_uint8 (writer, this->initiator_nonce.len); @@ -217,7 +210,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create( INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -231,8 +223,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create( .get_initiator_nonce = _get_initiator_nonce, .get_initiator_value = _get_initiator_value, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_FINISH, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_FINISH }, .hash_algo = hash_algo, .initiator_value = initiator_value, .initiator_nonce = chunk_clone(initiator_nonce), @@ -252,7 +243,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -266,8 +256,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_finish_create_from_data(chunk_t value) .get_initiator_nonce = _get_initiator_nonce, .get_initiator_value = _get_initiator_value, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_FINISH, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_FINISH }, .value = chunk_clone(value), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c index 36266fe12..828c09605 100644 --- a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_req.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -49,14 +49,9 @@ struct private_tcg_pts_attr_dh_nonce_params_req_t { tcg_pts_attr_dh_nonce_params_req_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -84,13 +79,7 @@ struct private_tcg_pts_attr_dh_nonce_params_req_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_dh_nonce_params_req_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_dh_nonce_params_req_t *this) { return this->type; @@ -119,6 +108,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_DH_NONCE_PARAMS_REQ_SIZE); writer->write_uint8 (writer, PTS_DH_NONCE_PARAMS_REQ_RESERVED); writer->write_uint8 (writer, this->min_nonce_len); @@ -191,7 +184,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -204,8 +196,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create(u_int8_t min_nonce_len, .get_min_nonce_len = _get_min_nonce_len, .get_dh_groups = _get_dh_groups, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_PARAMS_REQ, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_PARAMS_REQ }, .min_nonce_len = min_nonce_len, .dh_groups = dh_groups, .ref = 1, @@ -224,7 +215,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -237,8 +227,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_req_create_from_data(chunk_t value) .get_min_nonce_len = _get_min_nonce_len, .get_dh_groups = _get_dh_groups, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_PARAMS_REQ, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_PARAMS_REQ }, .value = chunk_clone(value), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c index 09bfa3aac..66ac185b3 100644 --- a/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c +++ b/src/libpts/tcg/tcg_pts_attr_dh_nonce_params_resp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -55,14 +55,9 @@ struct private_tcg_pts_attr_dh_nonce_params_resp_t { tcg_pts_attr_dh_nonce_params_resp_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -100,13 +95,7 @@ struct private_tcg_pts_attr_dh_nonce_params_resp_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_dh_nonce_params_resp_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_dh_nonce_params_resp_t *this) { return this->type; @@ -135,6 +124,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_DH_NONCE_PARAMS_RESP_SIZE); writer->write_uint24(writer, PTS_DH_NONCE_PARAMS_RESP_RESERVED); writer->write_uint8 (writer, this->responder_nonce.len); @@ -233,7 +226,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -248,8 +240,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create(pts_dh_group_t dh_group, .get_responder_nonce = _get_responder_nonce, .get_responder_value = _get_responder_value, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_PARAMS_RESP, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_PARAMS_RESP }, .dh_group = dh_group, .hash_algo_set = hash_algo_set, .responder_nonce = chunk_clone(responder_nonce), @@ -270,7 +261,6 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -285,8 +275,7 @@ pa_tnc_attr_t *tcg_pts_attr_dh_nonce_params_resp_create_from_data(chunk_t value) .get_responder_nonce = _get_responder_nonce, .get_responder_value = _get_responder_value, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_DH_NONCE_PARAMS_RESP, + .type = { PEN_TCG, TCG_PTS_DH_NONCE_PARAMS_RESP }, .value = chunk_clone(value), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_file_meas.c b/src/libpts/tcg/tcg_pts_attr_file_meas.c index 737da65c1..01c4361e1 100644 --- a/src/libpts/tcg/tcg_pts_attr_file_meas.c +++ b/src/libpts/tcg/tcg_pts_attr_file_meas.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -64,14 +64,9 @@ struct private_tcg_pts_attr_file_meas_t { tcg_pts_attr_file_meas_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -94,13 +89,7 @@ struct private_tcg_pts_attr_file_meas_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_file_meas_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_file_meas_t *this) { return this->type; @@ -135,6 +124,10 @@ METHOD(pa_tnc_attr_t, build, void, chunk_t measurement; bool first = TRUE; + if (this->value.ptr) + { + return; + } number_of_files = this->measurements->get_file_count(this->measurements); request_id = this->measurements->get_request_id(this->measurements); @@ -254,7 +247,6 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -266,8 +258,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create(pts_file_meas_t *measurements) }, .get_measurements = _get_measurements, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_FILE_MEAS, + .type = { PEN_TCG, TCG_PTS_FILE_MEAS }, .measurements = measurements, .ref = 1, ); @@ -286,7 +277,6 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -298,8 +288,7 @@ pa_tnc_attr_t *tcg_pts_attr_file_meas_create_from_data(chunk_t data) }, .get_measurements = _get_measurements, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_FILE_MEAS, + .type = { PEN_TCG, TCG_PTS_FILE_MEAS }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c index 054285c4e..5eac5ecae 100644 --- a/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c +++ b/src/libpts/tcg/tcg_pts_attr_gen_attest_evid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -50,14 +50,9 @@ struct private_tcg_pts_attr_gen_attest_evid_t { tcg_pts_attr_gen_attest_evid_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -75,13 +70,7 @@ struct private_tcg_pts_attr_gen_attest_evid_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_gen_attest_evid_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_gen_attest_evid_t *this) { return this->type; @@ -110,6 +99,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_GEN_ATTEST_EVID_SIZE); writer->write_uint32 (writer, PTS_GEN_ATTEST_EVID_RESERVED); @@ -163,7 +156,6 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create() INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -174,8 +166,7 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create() .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GEN_ATTEST_EVID, + .type = { PEN_TCG, TCG_PTS_GEN_ATTEST_EVID }, .ref = 1, ); @@ -193,7 +184,6 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -204,8 +194,7 @@ pa_tnc_attr_t *tcg_pts_attr_gen_attest_evid_create_from_data(chunk_t data) .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GEN_ATTEST_EVID, + .type = { PEN_TCG, TCG_PTS_GEN_ATTEST_EVID }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_get_aik.c b/src/libpts/tcg/tcg_pts_attr_get_aik.c index 1875375a4..4b5eae7a7 100644 --- a/src/libpts/tcg/tcg_pts_attr_get_aik.c +++ b/src/libpts/tcg/tcg_pts_attr_get_aik.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -47,14 +47,9 @@ struct private_tcg_pts_attr_get_aik_t { tcg_pts_attr_get_aik_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -72,13 +67,7 @@ struct private_tcg_pts_attr_get_aik_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_get_aik_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_get_aik_t *this) { return this->type; @@ -107,6 +96,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_GET_AIK_SIZE); writer->write_uint32 (writer, PTS_GET_AIK_RESERVED); @@ -160,7 +153,6 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create() INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -171,8 +163,7 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create() .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GET_AIK, + .type = { PEN_TCG, TCG_PTS_GET_AIK }, .ref = 1, ); @@ -190,7 +181,6 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -201,8 +191,7 @@ pa_tnc_attr_t *tcg_pts_attr_get_aik_create_from_data(chunk_t data) .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GET_AIK, + .type = { PEN_TCG, TCG_PTS_GET_AIK }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c index cb6834ca5..0cfc7efa9 100644 --- a/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c +++ b/src/libpts/tcg/tcg_pts_attr_get_tpm_version_info.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -50,14 +50,9 @@ struct private_tcg_pts_attr_get_tpm_version_info_t { tcg_pts_attr_get_tpm_version_info_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -75,13 +70,7 @@ struct private_tcg_pts_attr_get_tpm_version_info_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_get_tpm_version_info_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_get_tpm_version_info_t *this) { return this->type; @@ -110,6 +99,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_GET_TPM_VER_INFO_SIZE); writer->write_uint32 (writer, PTS_GET_TPM_VER_INFO_RESERVED); @@ -163,7 +156,6 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create() INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -174,8 +166,7 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create() .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GET_TPM_VERSION_INFO, + .type = { PEN_TCG, TCG_PTS_GET_TPM_VERSION_INFO }, .ref = 1, ); @@ -193,7 +184,6 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -204,8 +194,7 @@ pa_tnc_attr_t *tcg_pts_attr_get_tpm_version_info_create_from_data(chunk_t data) .destroy = _destroy, }, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_GET_TPM_VERSION_INFO, + .type = { PEN_TCG, TCG_PTS_GET_TPM_VERSION_INFO }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_meas_algo.c b/src/libpts/tcg/tcg_pts_attr_meas_algo.c index ed520e3cd..bb95adc9e 100644 --- a/src/libpts/tcg/tcg_pts_attr_meas_algo.c +++ b/src/libpts/tcg/tcg_pts_attr_meas_algo.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -48,14 +48,9 @@ struct private_tcg_pts_attr_meas_algo_t { tcg_pts_attr_meas_algo_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -78,13 +73,7 @@ struct private_tcg_pts_attr_meas_algo_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_meas_algo_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_meas_algo_t *this) { return this->type; @@ -113,6 +102,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_MEAS_ALGO_SIZE); writer->write_uint16(writer, PTS_MEAS_ALGO_RESERVED); writer->write_uint16(writer, this->algorithms); @@ -175,7 +168,6 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -187,8 +179,8 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create(pts_meas_algorithms_t algorithms, }, .get_algorithms = _get_algorithms, }, - .vendor_id = PEN_TCG, - .type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO, + .type = { PEN_TCG, + selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO }, .algorithms = algorithms, .ref = 1, ); @@ -208,7 +200,6 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -220,8 +211,8 @@ pa_tnc_attr_t *tcg_pts_attr_meas_algo_create_from_data(chunk_t data, }, .get_algorithms = _get_algorithms, }, - .vendor_id = PEN_TCG, - .type = selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO, + .type = { PEN_TCG, + selection ? TCG_PTS_MEAS_ALGO_SELECTION : TCG_PTS_MEAS_ALGO }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_proto_caps.c b/src/libpts/tcg/tcg_pts_attr_proto_caps.c index 055c750ff..83665ff69 100644 --- a/src/libpts/tcg/tcg_pts_attr_proto_caps.c +++ b/src/libpts/tcg/tcg_pts_attr_proto_caps.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -48,14 +48,9 @@ struct private_tcg_pts_attr_proto_caps_t { tcg_pts_attr_proto_caps_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -78,13 +73,7 @@ struct private_tcg_pts_attr_proto_caps_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_proto_caps_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_proto_caps_t *this) { return this->type; @@ -113,6 +102,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_PROTO_CAPS_SIZE); writer->write_uint16(writer, PTS_PROTO_CAPS_RESERVED); writer->write_uint16(writer, this->flags); @@ -176,7 +169,6 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -188,8 +180,8 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create(pts_proto_caps_flag_t flags, }, .get_flags = _get_flags, }, - .vendor_id = PEN_TCG, - .type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS, + .type = { PEN_TCG, + request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS }, .flags = flags, .ref = 1, ); @@ -208,7 +200,6 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -220,8 +211,8 @@ pa_tnc_attr_t *tcg_pts_attr_proto_caps_create_from_data(chunk_t data, }, .get_flags = _get_flags, }, - .vendor_id = PEN_TCG, - .type = request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS, + .type = { PEN_TCG, + request ? TCG_PTS_REQ_PROTO_CAPS : TCG_PTS_PROTO_CAPS }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c index 17781f745..65bdff579 100644 --- a/src/libpts/tcg/tcg_pts_attr_req_file_meas.c +++ b/src/libpts/tcg/tcg_pts_attr_req_file_meas.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -54,14 +54,9 @@ struct private_tcg_pts_attr_req_file_meas_t { tcg_pts_attr_req_file_meas_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -99,13 +94,7 @@ struct private_tcg_pts_attr_req_file_meas_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_req_file_meas_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_req_file_meas_t *this) { return this->type; @@ -136,6 +125,10 @@ METHOD(pa_tnc_attr_t, build, void, chunk_t pathname; bio_writer_t *writer; + if (this->value.ptr) + { + return; + } if (this->directory_flag) { flags |= DIRECTORY_CONTENTS_FLAG; @@ -240,7 +233,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -255,8 +247,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create(bool directory_flag, .get_delimiter = _get_delimiter, .get_pathname = _get_pathname, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FILE_MEAS, + .type = { PEN_TCG, TCG_PTS_REQ_FILE_MEAS }, .directory_flag = directory_flag, .request_id = request_id, .delimiter = delimiter, @@ -278,7 +269,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -293,8 +283,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meas_create_from_data(chunk_t data) .get_delimiter = _get_delimiter, .get_pathname = _get_pathname, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FILE_MEAS, + .type = { PEN_TCG, TCG_PTS_REQ_FILE_MEAS }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c index bef6b5db6..eb5114172 100644 --- a/src/libpts/tcg/tcg_pts_attr_req_file_meta.c +++ b/src/libpts/tcg/tcg_pts_attr_req_file_meta.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -52,14 +52,9 @@ struct private_tcg_pts_attr_req_file_meta_t { tcg_pts_attr_req_file_meta_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -92,13 +87,7 @@ struct private_tcg_pts_attr_req_file_meta_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_req_file_meta_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_req_file_meta_t *this) { return this->type; @@ -129,6 +118,10 @@ METHOD(pa_tnc_attr_t, build, void, chunk_t pathname; bio_writer_t *writer; + if (this->value.ptr) + { + return; + } if (this->directory_flag) { flags |= DIRECTORY_CONTENTS_FLAG; @@ -226,7 +219,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create(bool directory_flag, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -240,8 +232,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create(bool directory_flag, .get_delimiter = _get_delimiter, .get_pathname = _get_pathname, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FILE_META, + .type = { PEN_TCG, TCG_PTS_REQ_FILE_META }, .directory_flag = directory_flag, .delimiter = delimiter, .pathname = strdup(pathname), @@ -262,7 +253,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -276,8 +266,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_file_meta_create_from_data(chunk_t data) .get_delimiter = _get_delimiter, .get_pathname = _get_pathname, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FILE_META, + .type = { PEN_TCG, TCG_PTS_REQ_FILE_META }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c index bfd108b9f..a631e9891 100644 --- a/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c +++ b/src/libpts/tcg/tcg_pts_attr_req_func_comp_evid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -73,14 +73,9 @@ struct private_tcg_pts_attr_req_func_comp_evid_t { tcg_pts_attr_req_func_comp_evid_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -140,13 +135,7 @@ static void free_entry(entry_t *this) } } -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_req_func_comp_evid_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_req_func_comp_evid_t *this) { return this->type; @@ -177,6 +166,10 @@ METHOD(pa_tnc_attr_t, build, void, enumerator_t *enumerator; entry_t *entry; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_REQ_FUNC_COMP_EVID_SIZE); enumerator = this->list->create_enumerator(this->list); @@ -320,7 +313,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create(void) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -334,8 +326,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create(void) .get_count = _get_count, .create_enumerator = _create_enumerator, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FUNC_COMP_EVID, + .type = { PEN_TCG, TCG_PTS_REQ_FUNC_COMP_EVID }, .list = linked_list_create(), .ref = 1, ); @@ -353,7 +344,6 @@ pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -367,8 +357,7 @@ pa_tnc_attr_t *tcg_pts_attr_req_func_comp_evid_create_from_data(chunk_t data) .get_count = _get_count, .create_enumerator = _create_enumerator, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_REQ_FUNC_COMP_EVID, + .type = { PEN_TCG, TCG_PTS_REQ_FUNC_COMP_EVID }, .list = linked_list_create(), .value = chunk_clone(data), .ref = 1, diff --git a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c index d2c197ac4..387f4a115 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c +++ b/src/libpts/tcg/tcg_pts_attr_simple_comp_evid.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -100,14 +100,9 @@ struct private_tcg_pts_attr_simple_comp_evid_t { tcg_pts_attr_simple_comp_evid_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -130,13 +125,7 @@ struct private_tcg_pts_attr_simple_comp_evid_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_simple_comp_evid_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_simple_comp_evid_t *this) { return this->type; @@ -185,16 +174,22 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; bool has_pcr_info; - char utc_time_buf[25]; + char utc_time_buf[25], *policy_uri; u_int8_t flags; + u_int16_t len; u_int32_t depth, extended_pcr; pts_comp_func_name_t *name; pts_meas_algorithms_t hash_algorithm; pts_pcr_transform_t transform; pts_comp_evid_validation_t validation; time_t measurement_time; - chunk_t measurement, utc_time, pcr_before, pcr_after, policy_uri; + chunk_t measurement, utc_time, pcr_before, pcr_after; + if (this->value.ptr) + { + return; + } + /* Extract parameters from comp_evidence_t object */ name = this->evidence->get_comp_func_name(this->evidence, &depth); @@ -234,8 +229,9 @@ METHOD(pa_tnc_attr_t, build, void, if (validation == PTS_COMP_EVID_VALIDATION_FAILED || validation == PTS_COMP_EVID_VALIDATION_PASSED) { - writer->write_uint16(writer, policy_uri.len); - writer->write_data (writer, policy_uri); + len = strlen(policy_uri); + writer->write_uint16(writer, len); + writer->write_data (writer, chunk_create(policy_uri, len)); } if (has_pcr_info) { @@ -409,8 +405,13 @@ METHOD(pa_tnc_attr_t, process, status_t, /* Add options */ if (has_validation) { - policy_uri = chunk_clone(policy_uri); - this->evidence->set_validation(this->evidence, validation, policy_uri); + char buf[BUF_LEN]; + size_t len; + + len = min(policy_uri.len, BUF_LEN-1); + memcpy(buf, policy_uri.ptr, len); + buf[len] = '\0'; + this->evidence->set_validation(this->evidence, validation, buf); } if (has_pcr_info) { @@ -460,7 +461,6 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -472,8 +472,7 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create(pts_comp_evidence_t *evid) }, .get_comp_evidence = _get_comp_evidence, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_SIMPLE_COMP_EVID, + .type = { PEN_TCG, TCG_PTS_SIMPLE_COMP_EVID }, .evidence = evid, .ref = 1, ); @@ -492,7 +491,6 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -504,8 +502,7 @@ pa_tnc_attr_t *tcg_pts_attr_simple_comp_evid_create_from_data(chunk_t data) }, .get_comp_evidence = _get_comp_evidence, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_SIMPLE_COMP_EVID, + .type = { PEN_TCG, TCG_PTS_SIMPLE_COMP_EVID }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c index 27720d509..8d2d4f82d 100644 --- a/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c +++ b/src/libpts/tcg/tcg_pts_attr_simple_evid_final.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -58,14 +58,9 @@ struct private_tcg_pts_attr_simple_evid_final_t { tcg_pts_attr_simple_evid_final_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -113,13 +108,7 @@ struct private_tcg_pts_attr_simple_evid_final_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_simple_evid_final_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_simple_evid_final_t *this) { return this->type; @@ -169,6 +158,10 @@ METHOD(pa_tnc_attr_t, build, void, bio_writer_t *writer; u_int8_t flags; + if (this->value.ptr) + { + return; + } flags = this->flags & PTS_SIMPLE_EVID_FINAL_FLAG_MASK; if (this->has_evid_sig) @@ -333,7 +326,6 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(u_int8_t flags, INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -347,8 +339,7 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create(u_int8_t flags, .get_evid_sig = _get_evid_sig, .set_evid_sig = _set_evid_sig, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_SIMPLE_EVID_FINAL, + .type = { PEN_TCG, TCG_PTS_SIMPLE_EVID_FINAL }, .flags = flags, .comp_hash_algorithm = comp_hash_algorithm, .pcr_comp = pcr_comp, @@ -370,7 +361,6 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -384,8 +374,7 @@ pa_tnc_attr_t *tcg_pts_attr_simple_evid_final_create_from_data(chunk_t data) .get_evid_sig = _get_evid_sig, .set_evid_sig = _set_evid_sig, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_SIMPLE_EVID_FINAL, + .type = { PEN_TCG, TCG_PTS_SIMPLE_EVID_FINAL }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c index 944a12cc9..8d1e78f18 100644 --- a/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c +++ b/src/libpts/tcg/tcg_pts_attr_tpm_version_info.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -49,14 +49,9 @@ struct private_tcg_pts_attr_tpm_version_info_t { tcg_pts_attr_tpm_version_info_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -79,13 +74,7 @@ struct private_tcg_pts_attr_tpm_version_info_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_tpm_version_info_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_tpm_version_info_t *this) { return this->type; @@ -114,6 +103,10 @@ METHOD(pa_tnc_attr_t, build, void, { bio_writer_t *writer; + if (this->value.ptr) + { + return; + } writer = bio_writer_create(PTS_TPM_VER_INFO_SIZE); writer->write_data(writer, this->tpm_version_info); @@ -181,7 +174,6 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -194,8 +186,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create(chunk_t tpm_version_info) .get_tpm_version_info = _get_tpm_version_info, .set_tpm_version_info = _set_tpm_version_info, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_TPM_VERSION_INFO, + .type = { PEN_TCG, TCG_PTS_TPM_VERSION_INFO }, .tpm_version_info = chunk_clone(tpm_version_info), .ref = 1, ); @@ -214,7 +205,6 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -227,8 +217,7 @@ pa_tnc_attr_t *tcg_pts_attr_tpm_version_info_create_from_data(chunk_t data) .get_tpm_version_info = _get_tpm_version_info, .set_tpm_version_info = _set_tpm_version_info, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_TPM_VERSION_INFO, + .type = { PEN_TCG, TCG_PTS_TPM_VERSION_INFO }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c index a9f4a115d..4f93ee885 100644 --- a/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c +++ b/src/libpts/tcg/tcg_pts_attr_unix_file_meta.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Sansar Choinyambuu + * Copyright (C) 2011-2012 Sansar Choinyambuu, Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -80,14 +80,9 @@ struct private_tcg_pts_attr_file_meta_t { tcg_pts_attr_file_meta_t public; /** - * Attribute vendor ID + * Vendor-specific attribute type */ - pen_t vendor_id; - - /** - * Attribute type - */ - u_int32_t type; + pen_type_t type; /** * Attribute value @@ -110,13 +105,7 @@ struct private_tcg_pts_attr_file_meta_t { refcount_t ref; }; -METHOD(pa_tnc_attr_t, get_vendor_id, pen_t, - private_tcg_pts_attr_file_meta_t *this) -{ - return this->vendor_id; -} - -METHOD(pa_tnc_attr_t, get_type, u_int32_t, +METHOD(pa_tnc_attr_t, get_type, pen_type_t, private_tcg_pts_attr_file_meta_t *this) { return this->type; @@ -148,6 +137,10 @@ METHOD(pa_tnc_attr_t, build, void, pts_file_metadata_t *entry; u_int64_t number_of_files; + if (this->value.ptr) + { + return; + } number_of_files = this->metadata->get_file_count(this->metadata); writer = bio_writer_create(PTS_FILE_META_SIZE); @@ -306,7 +299,6 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -318,8 +310,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create(pts_file_meta_t *metadata) }, .get_metadata = _get_metadata, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_UNIX_FILE_META, + .type = { PEN_TCG, TCG_PTS_UNIX_FILE_META }, .metadata = metadata, .ref = 1, ); @@ -338,7 +329,6 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data) INIT(this, .public = { .pa_tnc_attribute = { - .get_vendor_id = _get_vendor_id, .get_type = _get_type, .get_value = _get_value, .get_noskip_flag = _get_noskip_flag, @@ -350,8 +340,7 @@ pa_tnc_attr_t *tcg_pts_attr_unix_file_meta_create_from_data(chunk_t data) }, .get_metadata = _get_metadata, }, - .vendor_id = PEN_TCG, - .type = TCG_PTS_UNIX_FILE_META, + .type = { PEN_TCG, TCG_PTS_UNIX_FILE_META }, .value = chunk_clone(data), .ref = 1, ); diff --git a/src/libradius/Makefile.in b/src/libradius/Makefile.in index bcc38792a..15642db64 100644 --- a/src/libradius/Makefile.in +++ b/src/libradius/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -78,7 +79,7 @@ libradius_la_LIBADD = am_libradius_la_OBJECTS = radius_message.lo radius_socket.lo \ radius_client.lo radius_config.lo libradius_la_OBJECTS = $(am_libradius_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -104,6 +105,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -198,11 +200,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -219,11 +224,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -239,6 +245,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -248,7 +255,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libradius/radius_message.c b/src/libradius/radius_message.c index 17fa7357b..77f9b0398 100644 --- a/src/libradius/radius_message.c +++ b/src/libradius/radius_message.c @@ -286,14 +286,17 @@ METHOD(radius_message_t, add, void, this->msg->length = htons(ntohs(this->msg->length) + attribute->length); } -METHOD(radius_message_t, sign, void, +METHOD(radius_message_t, sign, bool, private_radius_message_t *this, u_int8_t *req_auth, chunk_t secret, hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth) { if (rng) { /* build Request-Authenticator */ - rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator); + if (!rng->get_bytes(rng, HASH_SIZE_MD5, this->msg->authenticator)) + { + return FALSE; + } } else { @@ -315,9 +318,12 @@ METHOD(radius_message_t, sign, void, /* build Message-Authenticator attribute, using 16 null bytes */ memset(buf, 0, sizeof(buf)); add(this, RAT_MESSAGE_AUTHENTICATOR, chunk_create(buf, sizeof(buf))); - signer->get_signature(signer, + if (!signer->get_signature(signer, chunk_create((u_char*)this->msg, ntohs(this->msg->length)), - ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5); + ((u_char*)this->msg) + ntohs(this->msg->length) - HASH_SIZE_MD5)) + { + return FALSE; + } } if (!rng) @@ -326,9 +332,13 @@ METHOD(radius_message_t, sign, void, /* build Response-Authenticator */ msg = chunk_create((u_char*)this->msg, ntohs(this->msg->length)); - hasher->get_hash(hasher, msg, NULL); - hasher->get_hash(hasher, secret, this->msg->authenticator); + if (!hasher->get_hash(hasher, msg, NULL) || + !hasher->get_hash(hasher, secret, this->msg->authenticator)) + { + return FALSE; + } } + return TRUE; } METHOD(radius_message_t, verify, bool, @@ -357,9 +367,9 @@ METHOD(radius_message_t, verify, bool, } /* verify Response-Authenticator */ - hasher->get_hash(hasher, msg, NULL); - hasher->get_hash(hasher, secret, buf); - if (!memeq(buf, res_auth, HASH_SIZE_MD5)) + if (!hasher->get_hash(hasher, msg, NULL) || + !hasher->get_hash(hasher, secret, buf) || + !memeq(buf, res_auth, HASH_SIZE_MD5)) { DBG1(DBG_CFG, "RADIUS Response-Authenticator verification failed"); return FALSE; diff --git a/src/libradius/radius_message.h b/src/libradius/radius_message.h index 6d0df53c3..f9c57c5ef 100644 --- a/src/libradius/radius_message.h +++ b/src/libradius/radius_message.h @@ -257,8 +257,9 @@ struct radius_message_t { * @param hasher MD5 hasher * @param rng RNG to create Request-Authenticator, NULL to omit * @param msg_auth calculate and add Message-Authenticator + * @return TRUE if signed successfully */ - void (*sign)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret, + bool (*sign)(radius_message_t *this, u_int8_t *req_auth, chunk_t secret, hasher_t *hasher, signer_t *signer, rng_t *rng, bool msg_auth); /** diff --git a/src/libradius/radius_socket.c b/src/libradius/radius_socket.c index 048c8814e..ba7cb14b0 100644 --- a/src/libradius/radius_socket.c +++ b/src/libradius/radius_socket.c @@ -148,8 +148,11 @@ METHOD(radius_socket_t, request, radius_message_t*, /* set Message Identifier */ request->set_identifier(request, this->identifier++); /* sign the request */ - request->sign(request, NULL, this->secret, this->hasher, this->signer, - rng, rng != NULL); + if (!request->sign(request, NULL, this->secret, this->hasher, this->signer, + rng, rng != NULL)) + { + return NULL; + } if (!check_connection(this, fd, port)) { @@ -257,8 +260,11 @@ static chunk_t decrypt_mppe_key(private_radius_socket_t *this, u_int16_t salt, while (c < C.ptr + C.len) { /* b(i) = MD5(S + c(i-1)) */ - this->hasher->get_hash(this->hasher, this->secret, NULL); - this->hasher->get_hash(this->hasher, seed, p); + if (!this->hasher->get_hash(this->hasher, this->secret, NULL) || + !this->hasher->get_hash(this->hasher, seed, p)) + { + return chunk_empty; + } /* p(i) = b(i) xor c(1) */ memxor(p, c, HASH_SIZE_MD5); @@ -358,14 +364,14 @@ radius_socket_t *radius_socket_create(char *address, u_int16_t auth_port, .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), ); - if (!this->hasher || !this->signer || !this->rng) + if (!this->hasher || !this->signer || !this->rng || + !this->signer->set_key(this->signer, secret)) { DBG1(DBG_CFG, "RADIUS initialization failed, HMAC/MD5/RNG required"); destroy(this); return NULL; } this->secret = secret; - this->signer->set_key(this->signer, secret); /* we use a random identifier, helps if we restart often */ this->identifier = random(); diff --git a/src/libsimaka/Makefile.in b/src/libsimaka/Makefile.in index 59919e559..cdc7799ae 100644 --- a/src/libsimaka/Makefile.in +++ b/src/libsimaka/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -78,7 +79,7 @@ libsimaka_la_LIBADD = am_libsimaka_la_OBJECTS = simaka_message.lo simaka_crypto.lo \ simaka_manager.lo libsimaka_la_OBJECTS = $(am_libsimaka_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -104,6 +105,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -198,11 +200,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -219,11 +224,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -239,6 +245,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -248,7 +255,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libsimaka/simaka_crypto.c b/src/libsimaka/simaka_crypto.c index 4819d1b99..92db19317 100644 --- a/src/libsimaka/simaka_crypto.c +++ b/src/libsimaka/simaka_crypto.c @@ -115,90 +115,128 @@ static void call_hook(private_simaka_crypto_t *this, chunk_t encr, chunk_t auth) mgr->key_hook(mgr, encr, auth); } -METHOD(simaka_crypto_t, derive_keys_full, chunk_t, +METHOD(simaka_crypto_t, derive_keys_full, bool, private_simaka_crypto_t *this, identification_t *id, - chunk_t data, chunk_t *mk) + chunk_t data, chunk_t *mk, chunk_t *msk) { - chunk_t str, msk, k_encr, k_auth; + chunk_t str, k_encr, k_auth; int i; /* For SIM: MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) * For AKA: MK = SHA1(Identity|IK|CK) */ - this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL); - this->hasher->allocate_hash(this->hasher, data, mk); + if (!this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL) || + !this->hasher->allocate_hash(this->hasher, data, mk)) + { + return FALSE; + } DBG3(DBG_LIB, "MK %B", mk); /* K_encr | K_auth | MSK | EMSK = prf() | prf() | prf() | prf() */ - this->prf->set_key(this->prf, *mk); + if (!this->prf->set_key(this->prf, *mk)) + { + chunk_clear(mk); + return FALSE; + } str = chunk_alloca(this->prf->get_block_size(this->prf) * 3); for (i = 0; i < 3; i++) { - this->prf->get_bytes(this->prf, chunk_empty, str.ptr + str.len / 3 * i); + if (!this->prf->get_bytes(this->prf, chunk_empty, + str.ptr + str.len / 3 * i)) + { + chunk_clear(mk); + return FALSE; + } } k_encr = chunk_create(str.ptr, KENCR_LEN); k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN); - msk = chunk_create(str.ptr + KENCR_LEN + KAUTH_LEN, MSK_LEN); DBG3(DBG_LIB, "K_encr %B\nK_auth %B\nMSK %B", &k_encr, &k_auth, &msk); - this->signer->set_key(this->signer, k_auth); - this->crypter->set_key(this->crypter, k_encr); + if (!this->signer->set_key(this->signer, k_auth) || + !this->crypter->set_key(this->crypter, k_encr)) + { + chunk_clear(mk); + return FALSE; + } + + *msk = chunk_clone(chunk_create(str.ptr + KENCR_LEN + KAUTH_LEN, MSK_LEN)); call_hook(this, k_encr, k_auth); this->derived = TRUE; - return chunk_clone(msk); + return TRUE; } -METHOD(simaka_crypto_t, derive_keys_reauth, void, +METHOD(simaka_crypto_t, derive_keys_reauth, bool, private_simaka_crypto_t *this, chunk_t mk) { chunk_t str, k_encr, k_auth; int i; /* K_encr | K_auth = prf() | prf() */ - this->prf->set_key(this->prf, mk); + if (!this->prf->set_key(this->prf, mk)) + { + return FALSE; + } str = chunk_alloca(this->prf->get_block_size(this->prf) * 2); for (i = 0; i < 2; i++) { - this->prf->get_bytes(this->prf, chunk_empty, str.ptr + str.len / 2 * i); + if (!this->prf->get_bytes(this->prf, chunk_empty, + str.ptr + str.len / 2 * i)) + { + return FALSE; + } } k_encr = chunk_create(str.ptr, KENCR_LEN); k_auth = chunk_create(str.ptr + KENCR_LEN, KAUTH_LEN); DBG3(DBG_LIB, "K_encr %B\nK_auth %B", &k_encr, &k_auth); - this->signer->set_key(this->signer, k_auth); - this->crypter->set_key(this->crypter, k_encr); + if (!this->signer->set_key(this->signer, k_auth) || + !this->crypter->set_key(this->crypter, k_encr)) + { + return FALSE; + } call_hook(this, k_encr, k_auth); this->derived = TRUE; + return TRUE; } -METHOD(simaka_crypto_t, derive_keys_reauth_msk, chunk_t, +METHOD(simaka_crypto_t, derive_keys_reauth_msk, bool, private_simaka_crypto_t *this, identification_t *id, chunk_t counter, - chunk_t nonce_s, chunk_t mk) + chunk_t nonce_s, chunk_t mk, chunk_t *msk) { char xkey[HASH_SIZE_SHA1]; - chunk_t str, msk; + chunk_t str; int i; - this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL); - this->hasher->get_hash(this->hasher, counter, NULL); - this->hasher->get_hash(this->hasher, nonce_s, NULL); - this->hasher->get_hash(this->hasher, mk, xkey); + if (!this->hasher->get_hash(this->hasher, id->get_encoding(id), NULL) || + !this->hasher->get_hash(this->hasher, counter, NULL) || + !this->hasher->get_hash(this->hasher, nonce_s, NULL) || + !this->hasher->get_hash(this->hasher, mk, xkey)) + { + return FALSE; + } /* MSK | EMSK = prf() | prf() | prf() | prf() */ - this->prf->set_key(this->prf, chunk_create(xkey, sizeof(xkey))); + if (!this->prf->set_key(this->prf, chunk_create(xkey, sizeof(xkey)))) + { + return FALSE; + } str = chunk_alloca(this->prf->get_block_size(this->prf) * 2); for (i = 0; i < 2; i++) { - this->prf->get_bytes(this->prf, chunk_empty, str.ptr + str.len / 2 * i); + if (!this->prf->get_bytes(this->prf, chunk_empty, + str.ptr + str.len / 2 * i)) + { + return FALSE; + } } - msk = chunk_create(str.ptr, MSK_LEN); - DBG3(DBG_LIB, "MSK %B", &msk); + *msk = chunk_clone(chunk_create(str.ptr, MSK_LEN)); + DBG3(DBG_LIB, "MSK %B", msk); - return chunk_clone(msk); + return TRUE; } METHOD(simaka_crypto_t, clear_keys, void, diff --git a/src/libsimaka/simaka_crypto.h b/src/libsimaka/simaka_crypto.h index d1830e658..c07755865 100644 --- a/src/libsimaka/simaka_crypto.h +++ b/src/libsimaka/simaka_crypto.h @@ -62,10 +62,11 @@ struct simaka_crypto_t { * @param id peer identity * @param data method specific data * @param mk chunk receiving allocated master key MK - * @return allocated MSK value + * @param msk chunk receiving allocated MSK + * @return TRUE if keys allocated and derived successfully */ - chunk_t (*derive_keys_full)(simaka_crypto_t *this, identification_t *id, - chunk_t data, chunk_t *mk); + bool (*derive_keys_full)(simaka_crypto_t *this, identification_t *id, + chunk_t data, chunk_t *mk, chunk_t *msk); /** * Derive k_encr/k_auth keys from MK using fast reauthentication. @@ -74,8 +75,9 @@ struct simaka_crypto_t { * internal crypter/signer instances. * * @param mk master key + * @return TRUE if keys derived successfully */ - void (*derive_keys_reauth)(simaka_crypto_t *this, chunk_t mk); + bool (*derive_keys_reauth)(simaka_crypto_t *this, chunk_t mk); /** * Derive MSK using fast reauthentication. @@ -84,10 +86,12 @@ struct simaka_crypto_t { * @param counter fast reauthentication counter value, network order * @param nonce_s server generated NONCE_S value * @param mk master key of last full authentication + * @param msk chunk receiving allocated MSK + * @return TRUE if MSK allocated and derived successfully */ - chunk_t (*derive_keys_reauth_msk)(simaka_crypto_t *this, - identification_t *id, chunk_t counter, - chunk_t nonce_s, chunk_t mk); + bool (*derive_keys_reauth_msk)(simaka_crypto_t *this, + identification_t *id, chunk_t counter, + chunk_t nonce_s, chunk_t mk, chunk_t *msk); /** * Clear keys (partially) derived. diff --git a/src/libsimaka/simaka_message.c b/src/libsimaka/simaka_message.c index a5754b985..aa36a0974 100644 --- a/src/libsimaka/simaka_message.c +++ b/src/libsimaka/simaka_message.c @@ -499,8 +499,10 @@ static bool decrypt(private_simaka_message_t *this) eap_type_names, this->hdr->type); return FALSE; } - - crypter->decrypt(crypter, this->encr, this->iv, &plain); + if (!crypter->decrypt(crypter, this->encr, this->iv, &plain)) + { + return FALSE; + } this->encrypted = TRUE; success = parse_attributes(this, plain); @@ -599,8 +601,8 @@ METHOD(simaka_message_t, verify, bool, return TRUE; } -METHOD(simaka_message_t, generate, chunk_t, - private_simaka_message_t *this, chunk_t sigdata) +METHOD(simaka_message_t, generate, bool, + private_simaka_message_t *this, chunk_t sigdata, chunk_t *gen) { /* buffers large enough for messages we generate */ char out_buf[1024], encr_buf[512]; @@ -771,13 +773,19 @@ METHOD(simaka_message_t, generate, chunk_t, out = chunk_skip(out, 4); rng = this->crypto->get_rng(this->crypto); - rng->get_bytes(rng, iv.len, out.ptr); + if (!rng->get_bytes(rng, iv.len, out.ptr)) + { + return FALSE; + } iv = chunk_clonea(chunk_create(out.ptr, iv.len)); out = chunk_skip(out, iv.len); /* inline encryption */ - crypter->encrypt(crypter, encr, iv, NULL); + if (!crypter->encrypt(crypter, encr, iv, NULL)) + { + return FALSE; + } /* add ENCR_DATA attribute */ hdr = (attr_hdr_t*)out.ptr; @@ -822,12 +830,16 @@ METHOD(simaka_message_t, generate, chunk_t, if (mac.len) { data = chunk_cata("cc", out, sigdata); - signer->get_signature(signer, data, mac.ptr); + if (!signer->get_signature(signer, data, mac.ptr)) + { + return FALSE; + } } call_hook(this, FALSE, FALSE); - return chunk_clone(out); + *gen = chunk_clone(out); + return TRUE; } METHOD(simaka_message_t, destroy, void, diff --git a/src/libsimaka/simaka_message.h b/src/libsimaka/simaka_message.h index 28fe21823..209067c70 100644 --- a/src/libsimaka/simaka_message.h +++ b/src/libsimaka/simaka_message.h @@ -236,9 +236,10 @@ struct simaka_message_t { * Generate a message, optionally encrypt attributes and create a MAC. * * @param sigdata additional data to include in signature, if any - * @return allocated data of generated message + * @param gen allocated generated data, if successful + * @return TRUE if successful */ - chunk_t (*generate)(simaka_message_t *this, chunk_t sigdata); + bool (*generate)(simaka_message_t *this, chunk_t sigdata, chunk_t *gen); /** * Destroy a simaka_message_t. diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index d33bee6c7..4912576df 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -3,81 +3,43 @@ include $(CLEAR_VARS) # copy-n-paste from Makefile.am LOCAL_SRC_FILES := \ -library.c library.h \ -chunk.c chunk.h \ -debug.c debug.h \ -enum.c enum.h \ -settings.h settings.c \ -printf_hook.c printf_hook.h \ -asn1/asn1.c asn1/asn1.h \ -asn1/asn1_parser.c asn1/asn1_parser.h \ -asn1/oid.c asn1/oid.h \ -bio/bio_reader.h bio/bio_reader.c bio/bio_writer.h bio/bio_writer.c \ -crypto/crypters/crypter.c crypto/crypters/crypter.h \ -crypto/hashers/hasher.h crypto/hashers/hasher.c \ -crypto/pkcs9.c crypto/pkcs9.h \ -crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords.h \ -crypto/prfs/prf.c crypto/prfs/prf.h \ -crypto/rngs/rng.c crypto/rngs/rng.h \ -crypto/prf_plus.h crypto/prf_plus.c \ -crypto/signers/signer.c crypto/signers/signer.h \ -crypto/crypto_factory.c crypto/crypto_factory.h \ -crypto/crypto_tester.c crypto/crypto_tester.h \ -crypto/diffie_hellman.c crypto/diffie_hellman.h \ -crypto/aead.c crypto/aead.h \ -crypto/transform.c crypto/transform.h \ -credentials/credential_factory.c credentials/credential_factory.h \ -credentials/builder.c credentials/builder.h \ -credentials/cred_encoding.c credentials/cred_encoding.h \ -credentials/keys/private_key.c credentials/keys/private_key.h \ -credentials/keys/public_key.c credentials/keys/public_key.h \ -credentials/keys/shared_key.c credentials/keys/shared_key.h \ -credentials/certificates/certificate.c credentials/certificates/certificate.h \ -credentials/certificates/x509.h credentials/certificates/ac.h \ -credentials/certificates/crl.h credentials/certificates/crl.c \ -credentials/certificates/pkcs10.h \ -credentials/certificates/ocsp_request.h \ -credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ -credentials/certificates/pgp_certificate.h \ -credentials/ietf_attributes/ietf_attributes.c credentials/ietf_attributes/ietf_attributes.h \ -credentials/credential_manager.c credentials/credential_manager.h \ -credentials/sets/auth_cfg_wrapper.c credentials/sets/auth_cfg_wrapper.h \ -credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \ -credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ -credentials/sets/mem_cred.c credentials/sets/mem_cred.h \ -credentials/sets/callback_cred.c credentials/sets/callback_cred.h \ -credentials/auth_cfg.c credentials/auth_cfg.h credentials/credential_set.h \ -credentials/cert_validator.h database/database.h database/database.c \ -database/database_factory.h database/database_factory.c \ -fetcher/fetcher.h fetcher/fetcher.c fetcher/fetcher_manager.h fetcher/fetcher_manager.c \ -eap/eap.h eap/eap.c \ -pen/pen.h pen/pen.c \ -plugins/plugin_loader.c plugins/plugin_loader.h plugins/plugin.h \ -plugins/plugin_feature.c plugins/plugin_feature.h \ -processing/jobs/job.h processing/jobs/job.c \ -processing/jobs/callback_job.c processing/jobs/callback_job.h \ -processing/processor.c processing/processor.h \ -processing/scheduler.c processing/scheduler.h \ -selectors/traffic_selector.c selectors/traffic_selector.h \ -threading/thread.h threading/thread.c \ -threading/thread_value.h threading/thread_value.c \ -threading/mutex.h threading/mutex.c threading/condvar.h \ -threading/rwlock.h threading/rwlock.c \ -threading/lock_profiler.h \ -utils.h utils.c \ -utils/host.c utils/host.h \ -utils/identification.c utils/identification.h \ -utils/lexparser.c utils/lexparser.h \ -utils/linked_list.c utils/linked_list.h \ -utils/hashtable.c utils/hashtable.h \ -utils/enumerator.c utils/enumerator.h \ -utils/optionsfrom.c utils/optionsfrom.h \ -utils/backtrace.c utils/backtrace.h +library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \ +asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \ +crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \ +crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \ +crypto/prfs/prf.c crypto/prfs/mac_prf.c \ +crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \ +crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \ +crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \ +credentials/credential_factory.c credentials/builder.c \ +credentials/cred_encoding.c credentials/keys/private_key.c \ +credentials/keys/public_key.c credentials/keys/shared_key.c \ +credentials/certificates/certificate.c credentials/certificates/crl.c \ +credentials/certificates/ocsp_response.c \ +credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \ +credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ +credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ +credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ +database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \ +ipsec/ipsec_types.c \ +pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \ +processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \ +selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ +threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ +utils.c utils/host.c utils/packet.c utils/identification.c utils/lexparser.c \ +utils/linked_list.c utils/blocking_queue.c utils/hashtable.c utils/enumerator.c \ +utils/optionsfrom.c utils/capabilities.c utils/backtrace.c utils/tun_device.c # adding the plugin source files LOCAL_SRC_FILES += $(call add_plugin, aes) +LOCAL_SRC_FILES += $(call add_plugin, curl) +ifneq ($(call plugin_enabled, curl),) +LOCAL_C_INCLUDES += $(libcurl_PATH) +LOCAL_SHARED_LIBRARIES += libcurl +endif + LOCAL_SRC_FILES += $(call add_plugin, des) LOCAL_SRC_FILES += $(call add_plugin, fips-prf) @@ -94,9 +56,11 @@ LOCAL_SRC_FILES += $(call add_plugin, md4) LOCAL_SRC_FILES += $(call add_plugin, md5) +LOCAL_SRC_FILES += $(call add_plugin, nonce) + LOCAL_SRC_FILES += $(call add_plugin, openssl) ifneq ($(call plugin_enabled, openssl),) -LOCAL_C_INCLUDES += external/openssl/include +LOCAL_C_INCLUDES += $(openssl_PATH) LOCAL_SHARED_LIBRARIES += libcrypto endif @@ -104,6 +68,8 @@ LOCAL_SRC_FILES += $(call add_plugin, pem) LOCAL_SRC_FILES += $(call add_plugin, pkcs1) +LOCAL_SRC_FILES += $(call add_plugin, pkcs8) + LOCAL_SRC_FILES += $(call add_plugin, pkcs11) LOCAL_SRC_FILES += $(call add_plugin, pubkey) diff --git a/src/libstrongswan/AndroidConfigLocal.h b/src/libstrongswan/AndroidConfigLocal.h index a6da3276a..ee29c1693 100644 --- a/src/libstrongswan/AndroidConfigLocal.h +++ b/src/libstrongswan/AndroidConfigLocal.h @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2010 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + /* stuff defined in AndroidConfig.h, which is included using the -include * command-line option, thus cannot be undefined using -U CFLAGS options. * the reason we have to undefine these flags in the first place, is that diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 7bb0812bd..463d57d95 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -1,81 +1,75 @@ ipseclib_LTLIBRARIES = libstrongswan.la libstrongswan_la_SOURCES = \ -library.c library.h \ -chunk.c chunk.h \ -debug.c debug.h \ -enum.c enum.h \ -settings.h settings.c \ -printf_hook.c printf_hook.h \ -asn1/asn1.c asn1/asn1.h \ -asn1/asn1_parser.c asn1/asn1_parser.h \ -asn1/oid.c asn1/oid.h \ -bio/bio_reader.h bio/bio_reader.c bio/bio_writer.h bio/bio_writer.c \ -crypto/crypters/crypter.c crypto/crypters/crypter.h \ -crypto/hashers/hasher.h crypto/hashers/hasher.c \ -crypto/pkcs9.c crypto/pkcs9.h \ -crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords.h \ -crypto/prfs/prf.c crypto/prfs/prf.h \ -crypto/rngs/rng.c crypto/rngs/rng.h \ -crypto/prf_plus.h crypto/prf_plus.c \ -crypto/signers/signer.c crypto/signers/signer.h \ -crypto/crypto_factory.c crypto/crypto_factory.h \ -crypto/crypto_tester.c crypto/crypto_tester.h \ -crypto/diffie_hellman.c crypto/diffie_hellman.h \ -crypto/aead.c crypto/aead.h \ -crypto/transform.c crypto/transform.h \ -credentials/credential_factory.c credentials/credential_factory.h \ -credentials/builder.c credentials/builder.h \ -credentials/cred_encoding.c credentials/cred_encoding.h \ -credentials/keys/private_key.c credentials/keys/private_key.h \ -credentials/keys/public_key.c credentials/keys/public_key.h \ -credentials/keys/shared_key.c credentials/keys/shared_key.h \ -credentials/certificates/certificate.c credentials/certificates/certificate.h \ -credentials/certificates/x509.h credentials/certificates/ac.h \ -credentials/certificates/crl.h credentials/certificates/crl.c \ -credentials/certificates/pkcs10.h \ -credentials/certificates/ocsp_request.h \ -credentials/certificates/ocsp_response.h credentials/certificates/ocsp_response.c \ +library.c chunk.c debug.c enum.c settings.c printf_hook.c asn1/asn1.c \ +asn1/asn1_parser.c asn1/oid.c bio/bio_reader.c bio/bio_writer.c \ +crypto/crypters/crypter.c crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \ +crypto/proposal/proposal_keywords.c crypto/proposal/proposal_keywords_static.c \ +crypto/prfs/prf.c crypto/prfs/mac_prf.c \ +crypto/rngs/rng.c crypto/prf_plus.c crypto/signers/signer.c \ +crypto/signers/mac_signer.c crypto/crypto_factory.c crypto/crypto_tester.c \ +crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \ +credentials/credential_factory.c credentials/builder.c \ +credentials/cred_encoding.c credentials/keys/private_key.c \ +credentials/keys/public_key.c credentials/keys/shared_key.c \ +credentials/certificates/certificate.c credentials/certificates/crl.c \ +credentials/certificates/ocsp_response.c \ +credentials/ietf_attributes/ietf_attributes.c credentials/credential_manager.c \ +credentials/sets/auth_cfg_wrapper.c credentials/sets/ocsp_response_wrapper.c \ +credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ +credentials/sets/callback_cred.c credentials/auth_cfg.c database/database.c \ +database/database_factory.c fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \ +ipsec/ipsec_types.c \ +pen/pen.c plugins/plugin_loader.c plugins/plugin_feature.c processing/jobs/job.c \ +processing/jobs/callback_job.c processing/processor.c processing/scheduler.c \ +selectors/traffic_selector.c threading/thread.c threading/thread_value.c \ +threading/mutex.c threading/semaphore.c threading/rwlock.c threading/spinlock.c \ +utils.c utils/host.c utils/packet.c utils/identification.c utils/lexparser.c \ +utils/linked_list.c utils/blocking_queue.c utils/hashtable.c utils/enumerator.c \ +utils/optionsfrom.c utils/capabilities.c utils/backtrace.c utils/tun_device.c + +if USE_DEV_HEADERS +strongswan_includedir = ${dev_headers} +nobase_strongswan_include_HEADERS = \ +library.h chunk.h debug.h enum.h settings.h printf_hook.h \ +asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \ +crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \ +crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \ +crypto/proposal/proposal_keywords_static.h \ +crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \ +crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \ +crypto/crypto_factory.h crypto/crypto_tester.h crypto/diffie_hellman.h \ +crypto/aead.h crypto/transform.h \ +credentials/credential_factory.h credentials/builder.h \ +credentials/cred_encoding.h credentials/keys/private_key.h \ +credentials/keys/public_key.h credentials/keys/shared_key.h \ +credentials/certificates/certificate.h credentials/certificates/x509.h \ +credentials/certificates/ac.h credentials/certificates/crl.h \ +credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \ +credentials/certificates/ocsp_response.h \ credentials/certificates/pgp_certificate.h \ -credentials/ietf_attributes/ietf_attributes.c credentials/ietf_attributes/ietf_attributes.h \ -credentials/credential_manager.c credentials/credential_manager.h \ -credentials/sets/auth_cfg_wrapper.c credentials/sets/auth_cfg_wrapper.h \ -credentials/sets/ocsp_response_wrapper.c credentials/sets/ocsp_response_wrapper.h \ -credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ -credentials/sets/mem_cred.c credentials/sets/mem_cred.h \ -credentials/sets/callback_cred.c credentials/sets/callback_cred.h \ -credentials/auth_cfg.c credentials/auth_cfg.h credentials/credential_set.h \ -credentials/cert_validator.h database/database.h database/database.c \ -database/database_factory.h database/database_factory.c \ -fetcher/fetcher.h fetcher/fetcher.c fetcher/fetcher_manager.h fetcher/fetcher_manager.c \ -eap/eap.h eap/eap.c \ -pen/pen.h pen/pen.c \ -plugins/plugin_loader.c plugins/plugin_loader.h plugins/plugin.h \ -plugins/plugin_feature.c plugins/plugin_feature.h \ -processing/jobs/job.h processing/jobs/job.c \ -processing/jobs/callback_job.c processing/jobs/callback_job.h \ -processing/processor.c processing/processor.h \ -processing/scheduler.c processing/scheduler.h \ -selectors/traffic_selector.c selectors/traffic_selector.h \ -threading/thread.h threading/thread.c \ -threading/thread_value.h threading/thread_value.c \ -threading/mutex.h threading/mutex.c threading/condvar.h \ -threading/rwlock.h threading/rwlock.c \ -threading/lock_profiler.h \ -utils.h utils.c \ -utils/host.c utils/host.h \ -utils/identification.c utils/identification.h \ -utils/lexparser.c utils/lexparser.h \ -utils/linked_list.c utils/linked_list.h \ -utils/hashtable.c utils/hashtable.h \ -utils/enumerator.c utils/enumerator.h \ -utils/optionsfrom.c utils/optionsfrom.h \ -utils/backtrace.c utils/backtrace.h - +credentials/ietf_attributes/ietf_attributes.h \ +credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \ +credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \ +credentials/sets/mem_cred.h credentials/sets/callback_cred.h \ +credentials/auth_cfg.h credentials/credential_set.h credentials/cert_validator.h \ +database/database.h database/database_factory.h fetcher/fetcher.h \ +fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \ +plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \ +processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \ +processing/scheduler.h selectors/traffic_selector.h \ +threading/thread.h threading/thread_value.h \ +threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \ +threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \ +utils.h utils/host.h utils/packet.h utils/identification.h utils/lexparser.h \ +utils/linked_list.h utils/blocking_queue.h utils/hashtable.h utils/enumerator.h \ +utils/optionsfrom.h utils/capabilities.h utils/backtrace.h utils/tun_device.h \ +utils/leak_detective.h integrity_checker.h +endif library.lo : $(top_builddir)/config.status -libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) +libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) $(RTLIB) $(BFDLIB) INCLUDES = -I$(top_srcdir)/src/libstrongswan AM_CFLAGS = \ @@ -86,8 +80,7 @@ AM_CFLAGS = \ if USE_LEAK_DETECTIVE AM_CFLAGS += -DLEAK_DETECTIVE - libstrongswan_la_SOURCES += \ - utils/leak_detective.c utils/leak_detective.h + libstrongswan_la_SOURCES += utils/leak_detective.c endif if USE_LOCK_PROFILER @@ -96,26 +89,29 @@ endif if USE_INTEGRITY_TEST AM_CFLAGS += -DINTEGRITY_TEST - libstrongswan_la_SOURCES += \ - integrity_checker.c integrity_checker.h + libstrongswan_la_SOURCES += integrity_checker.c endif if USE_VSTR libstrongswan_la_LIBADD += -lvstr endif +if USE_LIBCAP + libstrongswan_la_LIBADD += -lcap +endif + EXTRA_DIST = \ asn1/oid.txt asn1/oid.pl \ -crypto/proposal/proposal_keywords.txt \ +crypto/proposal/proposal_keywords_static.txt \ Android.mk AndroidConfigLocal.h BUILT_SOURCES = \ $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \ -$(srcdir)/crypto/proposal/proposal_keywords.c +$(srcdir)/crypto/proposal/proposal_keywords_static.c MAINTAINERCLEANFILES = \ $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \ -$(srcdir)/crypto/proposal/proposal_keywords.c +$(srcdir)/crypto/proposal/proposal_keywords_static.c $(srcdir)/asn1/oid.c : $(srcdir)/asn1/oid.pl $(srcdir)/asn1/oid.txt (cd $(srcdir)/asn1/ && $(PERL) oid.pl) @@ -123,10 +119,10 @@ $(srcdir)/asn1/oid.c : $(srcdir)/asn1/oid.pl $(srcdir)/asn1/oid.txt $(srcdir)/asn1/oid.h : $(srcdir)/asn1/oid.pl $(srcdir)/asn1/oid.txt (cd $(srcdir)/asn1/ && $(PERL) oid.pl) -$(srcdir)/crypto/proposal/proposal_keywords.c: $(srcdir)/crypto/proposal/proposal_keywords.txt \ - $(srcdir)/crypto/proposal/proposal_keywords.h - $(GPERF) -N proposal_get_token -m 10 -C -G -c -t -D < \ - $(srcdir)/crypto/proposal/proposal_keywords.txt > $@ +$(srcdir)/crypto/proposal/proposal_keywords_static.c: $(srcdir)/crypto/proposal/proposal_keywords_static.txt \ + $(srcdir)/crypto/proposal/proposal_keywords_static.h + $(GPERF) -N proposal_get_token_static -m 10 -C -G -c -t -D < \ + $(srcdir)/crypto/proposal/proposal_keywords_static.txt > $@ # build plugins with their own Makefile @@ -208,6 +204,13 @@ if MONOLITHIC endif endif +if USE_NONCE + SUBDIRS += plugins/nonce +if MONOLITHIC + libstrongswan_la_LIBADD += plugins/nonce/libstrongswan-nonce.la +endif +endif + if USE_HMAC SUBDIRS += plugins/hmac if MONOLITHIC diff --git a/src/libstrongswan/Makefile.in b/src/libstrongswan/Makefile.in index 68c83a5aa..aeebb25c0 100644 --- a/src/libstrongswan/Makefile.in +++ b/src/libstrongswan/Makefile.in @@ -15,6 +15,7 @@ @SET_MAKE@ + VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ @@ -35,91 +36,91 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @USE_LEAK_DETECTIVE_TRUE@am__append_1 = -DLEAK_DETECTIVE -@USE_LEAK_DETECTIVE_TRUE@am__append_2 = \ -@USE_LEAK_DETECTIVE_TRUE@ utils/leak_detective.c utils/leak_detective.h - +@USE_LEAK_DETECTIVE_TRUE@am__append_2 = utils/leak_detective.c @USE_LOCK_PROFILER_TRUE@am__append_3 = -DLOCK_PROFILER @USE_INTEGRITY_TEST_TRUE@am__append_4 = -DINTEGRITY_TEST -@USE_INTEGRITY_TEST_TRUE@am__append_5 = \ -@USE_INTEGRITY_TEST_TRUE@ integrity_checker.c integrity_checker.h - +@USE_INTEGRITY_TEST_TRUE@am__append_5 = integrity_checker.c @USE_VSTR_TRUE@am__append_6 = -lvstr -@USE_AF_ALG_TRUE@am__append_7 = plugins/af_alg -@MONOLITHIC_TRUE@@USE_AF_ALG_TRUE@am__append_8 = plugins/af_alg/libstrongswan-af-alg.la -@USE_AES_TRUE@am__append_9 = plugins/aes -@MONOLITHIC_TRUE@@USE_AES_TRUE@am__append_10 = plugins/aes/libstrongswan-aes.la -@USE_DES_TRUE@am__append_11 = plugins/des -@MONOLITHIC_TRUE@@USE_DES_TRUE@am__append_12 = plugins/des/libstrongswan-des.la -@USE_BLOWFISH_TRUE@am__append_13 = plugins/blowfish -@MONOLITHIC_TRUE@@USE_BLOWFISH_TRUE@am__append_14 = plugins/blowfish/libstrongswan-blowfish.la -@USE_MD4_TRUE@am__append_15 = plugins/md4 -@MONOLITHIC_TRUE@@USE_MD4_TRUE@am__append_16 = plugins/md4/libstrongswan-md4.la -@USE_MD5_TRUE@am__append_17 = plugins/md5 -@MONOLITHIC_TRUE@@USE_MD5_TRUE@am__append_18 = plugins/md5/libstrongswan-md5.la -@USE_SHA1_TRUE@am__append_19 = plugins/sha1 -@MONOLITHIC_TRUE@@USE_SHA1_TRUE@am__append_20 = plugins/sha1/libstrongswan-sha1.la -@USE_SHA2_TRUE@am__append_21 = plugins/sha2 -@MONOLITHIC_TRUE@@USE_SHA2_TRUE@am__append_22 = plugins/sha2/libstrongswan-sha2.la -@USE_GMP_TRUE@am__append_23 = plugins/gmp -@MONOLITHIC_TRUE@@USE_GMP_TRUE@am__append_24 = plugins/gmp/libstrongswan-gmp.la -@USE_RANDOM_TRUE@am__append_25 = plugins/random -@MONOLITHIC_TRUE@@USE_RANDOM_TRUE@am__append_26 = plugins/random/libstrongswan-random.la -@USE_HMAC_TRUE@am__append_27 = plugins/hmac -@MONOLITHIC_TRUE@@USE_HMAC_TRUE@am__append_28 = plugins/hmac/libstrongswan-hmac.la -@USE_CMAC_TRUE@am__append_29 = plugins/cmac -@MONOLITHIC_TRUE@@USE_CMAC_TRUE@am__append_30 = plugins/cmac/libstrongswan-cmac.la -@USE_XCBC_TRUE@am__append_31 = plugins/xcbc -@MONOLITHIC_TRUE@@USE_XCBC_TRUE@am__append_32 = plugins/xcbc/libstrongswan-xcbc.la -@USE_X509_TRUE@am__append_33 = plugins/x509 -@MONOLITHIC_TRUE@@USE_X509_TRUE@am__append_34 = plugins/x509/libstrongswan-x509.la -@USE_REVOCATION_TRUE@am__append_35 = plugins/revocation -@MONOLITHIC_TRUE@@USE_REVOCATION_TRUE@am__append_36 = plugins/revocation/libstrongswan-revocation.la -@USE_CONSTRAINTS_TRUE@am__append_37 = plugins/constraints -@MONOLITHIC_TRUE@@USE_CONSTRAINTS_TRUE@am__append_38 = plugins/constraints/libstrongswan-constraints.la -@USE_PUBKEY_TRUE@am__append_39 = plugins/pubkey -@MONOLITHIC_TRUE@@USE_PUBKEY_TRUE@am__append_40 = plugins/pubkey/libstrongswan-pubkey.la -@USE_PKCS1_TRUE@am__append_41 = plugins/pkcs1 -@MONOLITHIC_TRUE@@USE_PKCS1_TRUE@am__append_42 = plugins/pkcs1/libstrongswan-pkcs1.la -@USE_PKCS8_TRUE@am__append_43 = plugins/pkcs8 -@MONOLITHIC_TRUE@@USE_PKCS8_TRUE@am__append_44 = plugins/pkcs8/libstrongswan-pkcs8.la -@USE_PGP_TRUE@am__append_45 = plugins/pgp -@MONOLITHIC_TRUE@@USE_PGP_TRUE@am__append_46 = plugins/pgp/libstrongswan-pgp.la -@USE_DNSKEY_TRUE@am__append_47 = plugins/dnskey -@MONOLITHIC_TRUE@@USE_DNSKEY_TRUE@am__append_48 = plugins/dnskey/libstrongswan-dnskey.la -@USE_PEM_TRUE@am__append_49 = plugins/pem -@MONOLITHIC_TRUE@@USE_PEM_TRUE@am__append_50 = plugins/pem/libstrongswan-pem.la -@USE_CURL_TRUE@am__append_51 = plugins/curl -@MONOLITHIC_TRUE@@USE_CURL_TRUE@am__append_52 = plugins/curl/libstrongswan-curl.la -@USE_SOUP_TRUE@am__append_53 = plugins/soup -@MONOLITHIC_TRUE@@USE_SOUP_TRUE@am__append_54 = plugins/soup/libstrongswan-soup.la -@USE_LDAP_TRUE@am__append_55 = plugins/ldap -@MONOLITHIC_TRUE@@USE_LDAP_TRUE@am__append_56 = plugins/ldap/libstrongswan-ldap.la -@USE_MYSQL_TRUE@am__append_57 = plugins/mysql -@MONOLITHIC_TRUE@@USE_MYSQL_TRUE@am__append_58 = plugins/mysql/libstrongswan-mysql.la -@USE_SQLITE_TRUE@am__append_59 = plugins/sqlite -@MONOLITHIC_TRUE@@USE_SQLITE_TRUE@am__append_60 = plugins/sqlite/libstrongswan-sqlite.la -@USE_PADLOCK_TRUE@am__append_61 = plugins/padlock -@MONOLITHIC_TRUE@@USE_PADLOCK_TRUE@am__append_62 = plugins/padlock/libstrongswan-padlock.la -@USE_OPENSSL_TRUE@am__append_63 = plugins/openssl -@MONOLITHIC_TRUE@@USE_OPENSSL_TRUE@am__append_64 = plugins/openssl/libstrongswan-openssl.la -@USE_GCRYPT_TRUE@am__append_65 = plugins/gcrypt -@MONOLITHIC_TRUE@@USE_GCRYPT_TRUE@am__append_66 = plugins/gcrypt/libstrongswan-gcrypt.la -@USE_FIPS_PRF_TRUE@am__append_67 = plugins/fips_prf -@MONOLITHIC_TRUE@@USE_FIPS_PRF_TRUE@am__append_68 = plugins/fips_prf/libstrongswan-fips-prf.la -@USE_AGENT_TRUE@am__append_69 = plugins/agent -@MONOLITHIC_TRUE@@USE_AGENT_TRUE@am__append_70 = plugins/agent/libstrongswan-agent.la -@USE_PKCS11_TRUE@am__append_71 = plugins/pkcs11 -@MONOLITHIC_TRUE@@USE_PKCS11_TRUE@am__append_72 = plugins/pkcs11/libstrongswan-pkcs11.la -@USE_CTR_TRUE@am__append_73 = plugins/ctr -@MONOLITHIC_TRUE@@USE_CTR_TRUE@am__append_74 = plugins/ctr/libstrongswan-ctr.la -@USE_CCM_TRUE@am__append_75 = plugins/ccm -@MONOLITHIC_TRUE@@USE_CCM_TRUE@am__append_76 = plugins/ccm/libstrongswan-ccm.la -@USE_GCM_TRUE@am__append_77 = plugins/gcm -@MONOLITHIC_TRUE@@USE_GCM_TRUE@am__append_78 = plugins/gcm/libstrongswan-gcm.la -@USE_TEST_VECTORS_TRUE@am__append_79 = plugins/test_vectors -@MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE@am__append_80 = plugins/test_vectors/libstrongswan-test-vectors.la +@USE_LIBCAP_TRUE@am__append_7 = -lcap +@USE_AF_ALG_TRUE@am__append_8 = plugins/af_alg +@MONOLITHIC_TRUE@@USE_AF_ALG_TRUE@am__append_9 = plugins/af_alg/libstrongswan-af-alg.la +@USE_AES_TRUE@am__append_10 = plugins/aes +@MONOLITHIC_TRUE@@USE_AES_TRUE@am__append_11 = plugins/aes/libstrongswan-aes.la +@USE_DES_TRUE@am__append_12 = plugins/des +@MONOLITHIC_TRUE@@USE_DES_TRUE@am__append_13 = plugins/des/libstrongswan-des.la +@USE_BLOWFISH_TRUE@am__append_14 = plugins/blowfish +@MONOLITHIC_TRUE@@USE_BLOWFISH_TRUE@am__append_15 = plugins/blowfish/libstrongswan-blowfish.la +@USE_MD4_TRUE@am__append_16 = plugins/md4 +@MONOLITHIC_TRUE@@USE_MD4_TRUE@am__append_17 = plugins/md4/libstrongswan-md4.la +@USE_MD5_TRUE@am__append_18 = plugins/md5 +@MONOLITHIC_TRUE@@USE_MD5_TRUE@am__append_19 = plugins/md5/libstrongswan-md5.la +@USE_SHA1_TRUE@am__append_20 = plugins/sha1 +@MONOLITHIC_TRUE@@USE_SHA1_TRUE@am__append_21 = plugins/sha1/libstrongswan-sha1.la +@USE_SHA2_TRUE@am__append_22 = plugins/sha2 +@MONOLITHIC_TRUE@@USE_SHA2_TRUE@am__append_23 = plugins/sha2/libstrongswan-sha2.la +@USE_GMP_TRUE@am__append_24 = plugins/gmp +@MONOLITHIC_TRUE@@USE_GMP_TRUE@am__append_25 = plugins/gmp/libstrongswan-gmp.la +@USE_RANDOM_TRUE@am__append_26 = plugins/random +@MONOLITHIC_TRUE@@USE_RANDOM_TRUE@am__append_27 = plugins/random/libstrongswan-random.la +@USE_NONCE_TRUE@am__append_28 = plugins/nonce +@MONOLITHIC_TRUE@@USE_NONCE_TRUE@am__append_29 = plugins/nonce/libstrongswan-nonce.la +@USE_HMAC_TRUE@am__append_30 = plugins/hmac +@MONOLITHIC_TRUE@@USE_HMAC_TRUE@am__append_31 = plugins/hmac/libstrongswan-hmac.la +@USE_CMAC_TRUE@am__append_32 = plugins/cmac +@MONOLITHIC_TRUE@@USE_CMAC_TRUE@am__append_33 = plugins/cmac/libstrongswan-cmac.la +@USE_XCBC_TRUE@am__append_34 = plugins/xcbc +@MONOLITHIC_TRUE@@USE_XCBC_TRUE@am__append_35 = plugins/xcbc/libstrongswan-xcbc.la +@USE_X509_TRUE@am__append_36 = plugins/x509 +@MONOLITHIC_TRUE@@USE_X509_TRUE@am__append_37 = plugins/x509/libstrongswan-x509.la +@USE_REVOCATION_TRUE@am__append_38 = plugins/revocation +@MONOLITHIC_TRUE@@USE_REVOCATION_TRUE@am__append_39 = plugins/revocation/libstrongswan-revocation.la +@USE_CONSTRAINTS_TRUE@am__append_40 = plugins/constraints +@MONOLITHIC_TRUE@@USE_CONSTRAINTS_TRUE@am__append_41 = plugins/constraints/libstrongswan-constraints.la +@USE_PUBKEY_TRUE@am__append_42 = plugins/pubkey +@MONOLITHIC_TRUE@@USE_PUBKEY_TRUE@am__append_43 = plugins/pubkey/libstrongswan-pubkey.la +@USE_PKCS1_TRUE@am__append_44 = plugins/pkcs1 +@MONOLITHIC_TRUE@@USE_PKCS1_TRUE@am__append_45 = plugins/pkcs1/libstrongswan-pkcs1.la +@USE_PKCS8_TRUE@am__append_46 = plugins/pkcs8 +@MONOLITHIC_TRUE@@USE_PKCS8_TRUE@am__append_47 = plugins/pkcs8/libstrongswan-pkcs8.la +@USE_PGP_TRUE@am__append_48 = plugins/pgp +@MONOLITHIC_TRUE@@USE_PGP_TRUE@am__append_49 = plugins/pgp/libstrongswan-pgp.la +@USE_DNSKEY_TRUE@am__append_50 = plugins/dnskey +@MONOLITHIC_TRUE@@USE_DNSKEY_TRUE@am__append_51 = plugins/dnskey/libstrongswan-dnskey.la +@USE_PEM_TRUE@am__append_52 = plugins/pem +@MONOLITHIC_TRUE@@USE_PEM_TRUE@am__append_53 = plugins/pem/libstrongswan-pem.la +@USE_CURL_TRUE@am__append_54 = plugins/curl +@MONOLITHIC_TRUE@@USE_CURL_TRUE@am__append_55 = plugins/curl/libstrongswan-curl.la +@USE_SOUP_TRUE@am__append_56 = plugins/soup +@MONOLITHIC_TRUE@@USE_SOUP_TRUE@am__append_57 = plugins/soup/libstrongswan-soup.la +@USE_LDAP_TRUE@am__append_58 = plugins/ldap +@MONOLITHIC_TRUE@@USE_LDAP_TRUE@am__append_59 = plugins/ldap/libstrongswan-ldap.la +@USE_MYSQL_TRUE@am__append_60 = plugins/mysql +@MONOLITHIC_TRUE@@USE_MYSQL_TRUE@am__append_61 = plugins/mysql/libstrongswan-mysql.la +@USE_SQLITE_TRUE@am__append_62 = plugins/sqlite +@MONOLITHIC_TRUE@@USE_SQLITE_TRUE@am__append_63 = plugins/sqlite/libstrongswan-sqlite.la +@USE_PADLOCK_TRUE@am__append_64 = plugins/padlock +@MONOLITHIC_TRUE@@USE_PADLOCK_TRUE@am__append_65 = plugins/padlock/libstrongswan-padlock.la +@USE_OPENSSL_TRUE@am__append_66 = plugins/openssl +@MONOLITHIC_TRUE@@USE_OPENSSL_TRUE@am__append_67 = plugins/openssl/libstrongswan-openssl.la +@USE_GCRYPT_TRUE@am__append_68 = plugins/gcrypt +@MONOLITHIC_TRUE@@USE_GCRYPT_TRUE@am__append_69 = plugins/gcrypt/libstrongswan-gcrypt.la +@USE_FIPS_PRF_TRUE@am__append_70 = plugins/fips_prf +@MONOLITHIC_TRUE@@USE_FIPS_PRF_TRUE@am__append_71 = plugins/fips_prf/libstrongswan-fips-prf.la +@USE_AGENT_TRUE@am__append_72 = plugins/agent +@MONOLITHIC_TRUE@@USE_AGENT_TRUE@am__append_73 = plugins/agent/libstrongswan-agent.la +@USE_PKCS11_TRUE@am__append_74 = plugins/pkcs11 +@MONOLITHIC_TRUE@@USE_PKCS11_TRUE@am__append_75 = plugins/pkcs11/libstrongswan-pkcs11.la +@USE_CTR_TRUE@am__append_76 = plugins/ctr +@MONOLITHIC_TRUE@@USE_CTR_TRUE@am__append_77 = plugins/ctr/libstrongswan-ctr.la +@USE_CCM_TRUE@am__append_78 = plugins/ccm +@MONOLITHIC_TRUE@@USE_CCM_TRUE@am__append_79 = plugins/ccm/libstrongswan-ccm.la +@USE_GCM_TRUE@am__append_80 = plugins/gcm +@MONOLITHIC_TRUE@@USE_GCM_TRUE@am__append_81 = plugins/gcm/libstrongswan-gcm.la +@USE_TEST_VECTORS_TRUE@am__append_82 = plugins/test_vectors +@MONOLITHIC_TRUE@@USE_TEST_VECTORS_TRUE@am__append_83 = plugins/test_vectors/libstrongswan-test-vectors.la subdir = src/libstrongswan -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +DIST_COMMON = $(am__nobase_strongswan_include_HEADERS_DIST) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ $(top_srcdir)/m4/config/ltoptions.m4 \ @@ -133,6 +134,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -156,101 +158,70 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(ipseclibdir)" +am__installdirs = "$(DESTDIR)$(ipseclibdir)" \ + "$(DESTDIR)$(strongswan_includedir)" LTLIBRARIES = $(ipseclib_LTLIBRARIES) am__DEPENDENCIES_1 = libstrongswan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__append_8) $(am__append_10) \ - $(am__append_12) $(am__append_14) $(am__append_16) \ - $(am__append_18) $(am__append_20) $(am__append_22) \ - $(am__append_24) $(am__append_26) $(am__append_28) \ - $(am__append_30) $(am__append_32) $(am__append_34) \ - $(am__append_36) $(am__append_38) $(am__append_40) \ - $(am__append_42) $(am__append_44) $(am__append_46) \ - $(am__append_48) $(am__append_50) $(am__append_52) \ - $(am__append_54) $(am__append_56) $(am__append_58) \ - $(am__append_60) $(am__append_62) $(am__append_64) \ - $(am__append_66) $(am__append_68) $(am__append_70) \ - $(am__append_72) $(am__append_74) $(am__append_76) \ - $(am__append_78) $(am__append_80) -am__libstrongswan_la_SOURCES_DIST = library.c library.h chunk.c \ - chunk.h debug.c debug.h enum.c enum.h settings.h settings.c \ - printf_hook.c printf_hook.h asn1/asn1.c asn1/asn1.h \ - asn1/asn1_parser.c asn1/asn1_parser.h asn1/oid.c asn1/oid.h \ - bio/bio_reader.h bio/bio_reader.c bio/bio_writer.h \ - bio/bio_writer.c crypto/crypters/crypter.c \ - crypto/crypters/crypter.h crypto/hashers/hasher.h \ - crypto/hashers/hasher.c crypto/pkcs9.c crypto/pkcs9.h \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__append_9) $(am__append_11) \ + $(am__append_13) $(am__append_15) $(am__append_17) \ + $(am__append_19) $(am__append_21) $(am__append_23) \ + $(am__append_25) $(am__append_27) $(am__append_29) \ + $(am__append_31) $(am__append_33) $(am__append_35) \ + $(am__append_37) $(am__append_39) $(am__append_41) \ + $(am__append_43) $(am__append_45) $(am__append_47) \ + $(am__append_49) $(am__append_51) $(am__append_53) \ + $(am__append_55) $(am__append_57) $(am__append_59) \ + $(am__append_61) $(am__append_63) $(am__append_65) \ + $(am__append_67) $(am__append_69) $(am__append_71) \ + $(am__append_73) $(am__append_75) $(am__append_77) \ + $(am__append_79) $(am__append_81) $(am__append_83) +am__libstrongswan_la_SOURCES_DIST = library.c chunk.c debug.c enum.c \ + settings.c printf_hook.c asn1/asn1.c asn1/asn1_parser.c \ + asn1/oid.c bio/bio_reader.c bio/bio_writer.c \ + crypto/crypters/crypter.c crypto/hashers/hasher.c \ + crypto/pkcs7.c crypto/pkcs9.c \ crypto/proposal/proposal_keywords.c \ - crypto/proposal/proposal_keywords.h crypto/prfs/prf.c \ - crypto/prfs/prf.h crypto/rngs/rng.c crypto/rngs/rng.h \ - crypto/prf_plus.h crypto/prf_plus.c crypto/signers/signer.c \ - crypto/signers/signer.h crypto/crypto_factory.c \ - crypto/crypto_factory.h crypto/crypto_tester.c \ - crypto/crypto_tester.h crypto/diffie_hellman.c \ - crypto/diffie_hellman.h crypto/aead.c crypto/aead.h \ - crypto/transform.c crypto/transform.h \ - credentials/credential_factory.c \ - credentials/credential_factory.h credentials/builder.c \ - credentials/builder.h credentials/cred_encoding.c \ - credentials/cred_encoding.h credentials/keys/private_key.c \ - credentials/keys/private_key.h credentials/keys/public_key.c \ - credentials/keys/public_key.h credentials/keys/shared_key.c \ - credentials/keys/shared_key.h \ + crypto/proposal/proposal_keywords_static.c crypto/prfs/prf.c \ + crypto/prfs/mac_prf.c crypto/rngs/rng.c crypto/prf_plus.c \ + crypto/signers/signer.c crypto/signers/mac_signer.c \ + crypto/crypto_factory.c crypto/crypto_tester.c \ + crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \ + credentials/credential_factory.c credentials/builder.c \ + credentials/cred_encoding.c credentials/keys/private_key.c \ + credentials/keys/public_key.c credentials/keys/shared_key.c \ credentials/certificates/certificate.c \ - credentials/certificates/certificate.h \ - credentials/certificates/x509.h credentials/certificates/ac.h \ - credentials/certificates/crl.h credentials/certificates/crl.c \ - credentials/certificates/pkcs10.h \ - credentials/certificates/ocsp_request.h \ - credentials/certificates/ocsp_response.h \ + credentials/certificates/crl.c \ credentials/certificates/ocsp_response.c \ - credentials/certificates/pgp_certificate.h \ credentials/ietf_attributes/ietf_attributes.c \ - credentials/ietf_attributes/ietf_attributes.h \ credentials/credential_manager.c \ - credentials/credential_manager.h \ credentials/sets/auth_cfg_wrapper.c \ - credentials/sets/auth_cfg_wrapper.h \ credentials/sets/ocsp_response_wrapper.c \ - credentials/sets/ocsp_response_wrapper.h \ - credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ - credentials/sets/mem_cred.c credentials/sets/mem_cred.h \ - credentials/sets/callback_cred.c \ - credentials/sets/callback_cred.h credentials/auth_cfg.c \ - credentials/auth_cfg.h credentials/credential_set.h \ - credentials/cert_validator.h database/database.h \ - database/database.c database/database_factory.h \ - database/database_factory.c fetcher/fetcher.h \ - fetcher/fetcher.c fetcher/fetcher_manager.h \ - fetcher/fetcher_manager.c eap/eap.h eap/eap.c pen/pen.h \ - pen/pen.c plugins/plugin_loader.c plugins/plugin_loader.h \ - plugins/plugin.h plugins/plugin_feature.c \ - plugins/plugin_feature.h processing/jobs/job.h \ - processing/jobs/job.c processing/jobs/callback_job.c \ - processing/jobs/callback_job.h processing/processor.c \ - processing/processor.h processing/scheduler.c \ - processing/scheduler.h selectors/traffic_selector.c \ - selectors/traffic_selector.h threading/thread.h \ - threading/thread.c threading/thread_value.h \ - threading/thread_value.c threading/mutex.h threading/mutex.c \ - threading/condvar.h threading/rwlock.h threading/rwlock.c \ - threading/lock_profiler.h utils.h utils.c utils/host.c \ - utils/host.h utils/identification.c utils/identification.h \ - utils/lexparser.c utils/lexparser.h utils/linked_list.c \ - utils/linked_list.h utils/hashtable.c utils/hashtable.h \ - utils/enumerator.c utils/enumerator.h utils/optionsfrom.c \ - utils/optionsfrom.h utils/backtrace.c utils/backtrace.h \ - utils/leak_detective.c utils/leak_detective.h \ - integrity_checker.c integrity_checker.h + credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ + credentials/sets/callback_cred.c credentials/auth_cfg.c \ + database/database.c database/database_factory.c \ + fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \ + ipsec/ipsec_types.c pen/pen.c plugins/plugin_loader.c \ + plugins/plugin_feature.c processing/jobs/job.c \ + processing/jobs/callback_job.c processing/processor.c \ + processing/scheduler.c selectors/traffic_selector.c \ + threading/thread.c threading/thread_value.c threading/mutex.c \ + threading/semaphore.c threading/rwlock.c threading/spinlock.c \ + utils.c utils/host.c utils/packet.c utils/identification.c \ + utils/lexparser.c utils/linked_list.c utils/blocking_queue.c \ + utils/hashtable.c utils/enumerator.c utils/optionsfrom.c \ + utils/capabilities.c utils/backtrace.c utils/tun_device.c \ + utils/leak_detective.c integrity_checker.c @USE_LEAK_DETECTIVE_TRUE@am__objects_1 = leak_detective.lo @USE_INTEGRITY_TEST_TRUE@am__objects_2 = integrity_checker.lo am_libstrongswan_la_OBJECTS = library.lo chunk.lo debug.lo enum.lo \ settings.lo printf_hook.lo asn1.lo asn1_parser.lo oid.lo \ - bio_reader.lo bio_writer.lo crypter.lo hasher.lo pkcs9.lo \ - proposal_keywords.lo prf.lo rng.lo prf_plus.lo signer.lo \ + bio_reader.lo bio_writer.lo crypter.lo hasher.lo pkcs7.lo \ + pkcs9.lo proposal_keywords.lo proposal_keywords_static.lo \ + prf.lo mac_prf.lo rng.lo prf_plus.lo signer.lo mac_signer.lo \ crypto_factory.lo crypto_tester.lo diffie_hellman.lo aead.lo \ transform.lo credential_factory.lo builder.lo cred_encoding.lo \ private_key.lo public_key.lo shared_key.lo certificate.lo \ @@ -258,14 +229,16 @@ am_libstrongswan_la_OBJECTS = library.lo chunk.lo debug.lo enum.lo \ credential_manager.lo auth_cfg_wrapper.lo \ ocsp_response_wrapper.lo cert_cache.lo mem_cred.lo \ callback_cred.lo auth_cfg.lo database.lo database_factory.lo \ - fetcher.lo fetcher_manager.lo eap.lo pen.lo plugin_loader.lo \ - plugin_feature.lo job.lo callback_job.lo processor.lo \ - scheduler.lo traffic_selector.lo thread.lo thread_value.lo \ - mutex.lo rwlock.lo utils.lo host.lo identification.lo \ - lexparser.lo linked_list.lo hashtable.lo enumerator.lo \ - optionsfrom.lo backtrace.lo $(am__objects_1) $(am__objects_2) + fetcher.lo fetcher_manager.lo eap.lo ipsec_types.lo pen.lo \ + plugin_loader.lo plugin_feature.lo job.lo callback_job.lo \ + processor.lo scheduler.lo traffic_selector.lo thread.lo \ + thread_value.lo mutex.lo semaphore.lo rwlock.lo spinlock.lo \ + utils.lo host.lo packet.lo identification.lo lexparser.lo \ + linked_list.lo blocking_queue.lo hashtable.lo enumerator.lo \ + optionsfrom.lo capabilities.lo backtrace.lo tun_device.lo \ + $(am__objects_1) $(am__objects_2) libstrongswan_la_OBJECTS = $(am_libstrongswan_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -287,6 +260,51 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ install-pdf-recursive install-ps-recursive install-recursive \ installcheck-recursive installdirs-recursive pdf-recursive \ ps-recursive uninstall-recursive +am__nobase_strongswan_include_HEADERS_DIST = library.h chunk.h debug.h \ + enum.h settings.h printf_hook.h asn1/asn1.h asn1/asn1_parser.h \ + asn1/oid.h bio/bio_reader.h bio/bio_writer.h \ + crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \ + crypto/pkcs7.h crypto/pkcs9.h \ + crypto/proposal/proposal_keywords.h \ + crypto/proposal/proposal_keywords_static.h crypto/prfs/prf.h \ + crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \ + crypto/prf_plus.h crypto/signers/signer.h \ + crypto/signers/mac_signer.h crypto/crypto_factory.h \ + crypto/crypto_tester.h crypto/diffie_hellman.h crypto/aead.h \ + crypto/transform.h credentials/credential_factory.h \ + credentials/builder.h credentials/cred_encoding.h \ + credentials/keys/private_key.h credentials/keys/public_key.h \ + credentials/keys/shared_key.h \ + credentials/certificates/certificate.h \ + credentials/certificates/x509.h credentials/certificates/ac.h \ + credentials/certificates/crl.h \ + credentials/certificates/pkcs10.h \ + credentials/certificates/ocsp_request.h \ + credentials/certificates/ocsp_response.h \ + credentials/certificates/pgp_certificate.h \ + credentials/ietf_attributes/ietf_attributes.h \ + credentials/credential_manager.h \ + credentials/sets/auth_cfg_wrapper.h \ + credentials/sets/ocsp_response_wrapper.h \ + credentials/sets/cert_cache.h credentials/sets/mem_cred.h \ + credentials/sets/callback_cred.h credentials/auth_cfg.h \ + credentials/credential_set.h credentials/cert_validator.h \ + database/database.h database/database_factory.h \ + fetcher/fetcher.h fetcher/fetcher_manager.h eap/eap.h \ + pen/pen.h ipsec/ipsec_types.h plugins/plugin_loader.h \ + plugins/plugin.h plugins/plugin_feature.h \ + processing/jobs/job.h processing/jobs/callback_job.h \ + processing/processor.h processing/scheduler.h \ + selectors/traffic_selector.h threading/thread.h \ + threading/thread_value.h threading/mutex.h threading/condvar.h \ + threading/spinlock.h threading/semaphore.h threading/rwlock.h \ + threading/rwlock_condvar.h threading/lock_profiler.h utils.h \ + utils/host.h utils/packet.h utils/identification.h \ + utils/lexparser.h utils/linked_list.h utils/blocking_queue.h \ + utils/hashtable.h utils/enumerator.h utils/optionsfrom.h \ + utils/capabilities.h utils/backtrace.h utils/tun_device.h \ + utils/leak_detective.h integrity_checker.h +HEADERS = $(nobase_strongswan_include_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ @@ -296,14 +314,14 @@ ETAGS = etags CTAGS = ctags DIST_SUBDIRS = . plugins/af_alg plugins/aes plugins/des \ plugins/blowfish plugins/md4 plugins/md5 plugins/sha1 \ - plugins/sha2 plugins/gmp plugins/random plugins/hmac \ - plugins/cmac plugins/xcbc plugins/x509 plugins/revocation \ - plugins/constraints plugins/pubkey plugins/pkcs1 plugins/pkcs8 \ - plugins/pgp plugins/dnskey plugins/pem plugins/curl \ - plugins/soup plugins/ldap plugins/mysql plugins/sqlite \ - plugins/padlock plugins/openssl plugins/gcrypt \ - plugins/fips_prf plugins/agent plugins/pkcs11 plugins/ctr \ - plugins/ccm plugins/gcm plugins/test_vectors + plugins/sha2 plugins/gmp plugins/random plugins/nonce \ + plugins/hmac plugins/cmac plugins/xcbc plugins/x509 \ + plugins/revocation plugins/constraints plugins/pubkey \ + plugins/pkcs1 plugins/pkcs8 plugins/pgp plugins/dnskey \ + plugins/pem plugins/curl plugins/soup plugins/ldap \ + plugins/mysql plugins/sqlite plugins/padlock plugins/openssl \ + plugins/gcrypt plugins/fips_prf plugins/agent plugins/pkcs11 \ + plugins/ctr plugins/ccm plugins/gcm plugins/test_vectors DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ @@ -338,6 +356,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -432,11 +451,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -453,11 +475,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -473,6 +496,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -482,7 +506,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -511,88 +534,93 @@ urandom_device = @urandom_device@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ ipseclib_LTLIBRARIES = libstrongswan.la -libstrongswan_la_SOURCES = library.c library.h chunk.c chunk.h debug.c \ - debug.h enum.c enum.h settings.h settings.c printf_hook.c \ - printf_hook.h asn1/asn1.c asn1/asn1.h asn1/asn1_parser.c \ - asn1/asn1_parser.h asn1/oid.c asn1/oid.h bio/bio_reader.h \ - bio/bio_reader.c bio/bio_writer.h bio/bio_writer.c \ - crypto/crypters/crypter.c crypto/crypters/crypter.h \ - crypto/hashers/hasher.h crypto/hashers/hasher.c crypto/pkcs9.c \ - crypto/pkcs9.h crypto/proposal/proposal_keywords.c \ - crypto/proposal/proposal_keywords.h crypto/prfs/prf.c \ - crypto/prfs/prf.h crypto/rngs/rng.c crypto/rngs/rng.h \ - crypto/prf_plus.h crypto/prf_plus.c crypto/signers/signer.c \ - crypto/signers/signer.h crypto/crypto_factory.c \ - crypto/crypto_factory.h crypto/crypto_tester.c \ - crypto/crypto_tester.h crypto/diffie_hellman.c \ - crypto/diffie_hellman.h crypto/aead.c crypto/aead.h \ - crypto/transform.c crypto/transform.h \ - credentials/credential_factory.c \ - credentials/credential_factory.h credentials/builder.c \ - credentials/builder.h credentials/cred_encoding.c \ - credentials/cred_encoding.h credentials/keys/private_key.c \ - credentials/keys/private_key.h credentials/keys/public_key.c \ - credentials/keys/public_key.h credentials/keys/shared_key.c \ - credentials/keys/shared_key.h \ +libstrongswan_la_SOURCES = library.c chunk.c debug.c enum.c settings.c \ + printf_hook.c asn1/asn1.c asn1/asn1_parser.c asn1/oid.c \ + bio/bio_reader.c bio/bio_writer.c crypto/crypters/crypter.c \ + crypto/hashers/hasher.c crypto/pkcs7.c crypto/pkcs9.c \ + crypto/proposal/proposal_keywords.c \ + crypto/proposal/proposal_keywords_static.c crypto/prfs/prf.c \ + crypto/prfs/mac_prf.c crypto/rngs/rng.c crypto/prf_plus.c \ + crypto/signers/signer.c crypto/signers/mac_signer.c \ + crypto/crypto_factory.c crypto/crypto_tester.c \ + crypto/diffie_hellman.c crypto/aead.c crypto/transform.c \ + credentials/credential_factory.c credentials/builder.c \ + credentials/cred_encoding.c credentials/keys/private_key.c \ + credentials/keys/public_key.c credentials/keys/shared_key.c \ credentials/certificates/certificate.c \ - credentials/certificates/certificate.h \ - credentials/certificates/x509.h credentials/certificates/ac.h \ - credentials/certificates/crl.h credentials/certificates/crl.c \ - credentials/certificates/pkcs10.h \ - credentials/certificates/ocsp_request.h \ - credentials/certificates/ocsp_response.h \ + credentials/certificates/crl.c \ credentials/certificates/ocsp_response.c \ - credentials/certificates/pgp_certificate.h \ credentials/ietf_attributes/ietf_attributes.c \ - credentials/ietf_attributes/ietf_attributes.h \ credentials/credential_manager.c \ - credentials/credential_manager.h \ credentials/sets/auth_cfg_wrapper.c \ - credentials/sets/auth_cfg_wrapper.h \ credentials/sets/ocsp_response_wrapper.c \ - credentials/sets/ocsp_response_wrapper.h \ - credentials/sets/cert_cache.c credentials/sets/cert_cache.h \ - credentials/sets/mem_cred.c credentials/sets/mem_cred.h \ - credentials/sets/callback_cred.c \ - credentials/sets/callback_cred.h credentials/auth_cfg.c \ - credentials/auth_cfg.h credentials/credential_set.h \ - credentials/cert_validator.h database/database.h \ - database/database.c database/database_factory.h \ - database/database_factory.c fetcher/fetcher.h \ - fetcher/fetcher.c fetcher/fetcher_manager.h \ - fetcher/fetcher_manager.c eap/eap.h eap/eap.c pen/pen.h \ - pen/pen.c plugins/plugin_loader.c plugins/plugin_loader.h \ - plugins/plugin.h plugins/plugin_feature.c \ - plugins/plugin_feature.h processing/jobs/job.h \ - processing/jobs/job.c processing/jobs/callback_job.c \ - processing/jobs/callback_job.h processing/processor.c \ - processing/processor.h processing/scheduler.c \ - processing/scheduler.h selectors/traffic_selector.c \ - selectors/traffic_selector.h threading/thread.h \ - threading/thread.c threading/thread_value.h \ - threading/thread_value.c threading/mutex.h threading/mutex.c \ - threading/condvar.h threading/rwlock.h threading/rwlock.c \ - threading/lock_profiler.h utils.h utils.c utils/host.c \ - utils/host.h utils/identification.c utils/identification.h \ - utils/lexparser.c utils/lexparser.h utils/linked_list.c \ - utils/linked_list.h utils/hashtable.c utils/hashtable.h \ - utils/enumerator.c utils/enumerator.h utils/optionsfrom.c \ - utils/optionsfrom.h utils/backtrace.c utils/backtrace.h \ + credentials/sets/cert_cache.c credentials/sets/mem_cred.c \ + credentials/sets/callback_cred.c credentials/auth_cfg.c \ + database/database.c database/database_factory.c \ + fetcher/fetcher.c fetcher/fetcher_manager.c eap/eap.c \ + ipsec/ipsec_types.c pen/pen.c plugins/plugin_loader.c \ + plugins/plugin_feature.c processing/jobs/job.c \ + processing/jobs/callback_job.c processing/processor.c \ + processing/scheduler.c selectors/traffic_selector.c \ + threading/thread.c threading/thread_value.c threading/mutex.c \ + threading/semaphore.c threading/rwlock.c threading/spinlock.c \ + utils.c utils/host.c utils/packet.c utils/identification.c \ + utils/lexparser.c utils/linked_list.c utils/blocking_queue.c \ + utils/hashtable.c utils/enumerator.c utils/optionsfrom.c \ + utils/capabilities.c utils/backtrace.c utils/tun_device.c \ $(am__append_2) $(am__append_5) +@USE_DEV_HEADERS_TRUE@strongswan_includedir = ${dev_headers} +@USE_DEV_HEADERS_TRUE@nobase_strongswan_include_HEADERS = \ +@USE_DEV_HEADERS_TRUE@library.h chunk.h debug.h enum.h settings.h printf_hook.h \ +@USE_DEV_HEADERS_TRUE@asn1/asn1.h asn1/asn1_parser.h asn1/oid.h bio/bio_reader.h bio/bio_writer.h \ +@USE_DEV_HEADERS_TRUE@crypto/crypters/crypter.h crypto/hashers/hasher.h crypto/mac.h \ +@USE_DEV_HEADERS_TRUE@crypto/pkcs7.h crypto/pkcs9.h crypto/proposal/proposal_keywords.h \ +@USE_DEV_HEADERS_TRUE@crypto/proposal/proposal_keywords_static.h \ +@USE_DEV_HEADERS_TRUE@crypto/prfs/prf.h crypto/prfs/mac_prf.h crypto/rngs/rng.h crypto/nonce_gen.h \ +@USE_DEV_HEADERS_TRUE@crypto/prf_plus.h crypto/signers/signer.h crypto/signers/mac_signer.h \ +@USE_DEV_HEADERS_TRUE@crypto/crypto_factory.h crypto/crypto_tester.h crypto/diffie_hellman.h \ +@USE_DEV_HEADERS_TRUE@crypto/aead.h crypto/transform.h \ +@USE_DEV_HEADERS_TRUE@credentials/credential_factory.h credentials/builder.h \ +@USE_DEV_HEADERS_TRUE@credentials/cred_encoding.h credentials/keys/private_key.h \ +@USE_DEV_HEADERS_TRUE@credentials/keys/public_key.h credentials/keys/shared_key.h \ +@USE_DEV_HEADERS_TRUE@credentials/certificates/certificate.h credentials/certificates/x509.h \ +@USE_DEV_HEADERS_TRUE@credentials/certificates/ac.h credentials/certificates/crl.h \ +@USE_DEV_HEADERS_TRUE@credentials/certificates/pkcs10.h credentials/certificates/ocsp_request.h \ +@USE_DEV_HEADERS_TRUE@credentials/certificates/ocsp_response.h \ +@USE_DEV_HEADERS_TRUE@credentials/certificates/pgp_certificate.h \ +@USE_DEV_HEADERS_TRUE@credentials/ietf_attributes/ietf_attributes.h \ +@USE_DEV_HEADERS_TRUE@credentials/credential_manager.h credentials/sets/auth_cfg_wrapper.h \ +@USE_DEV_HEADERS_TRUE@credentials/sets/ocsp_response_wrapper.h credentials/sets/cert_cache.h \ +@USE_DEV_HEADERS_TRUE@credentials/sets/mem_cred.h credentials/sets/callback_cred.h \ +@USE_DEV_HEADERS_TRUE@credentials/auth_cfg.h credentials/credential_set.h credentials/cert_validator.h \ +@USE_DEV_HEADERS_TRUE@database/database.h database/database_factory.h fetcher/fetcher.h \ +@USE_DEV_HEADERS_TRUE@fetcher/fetcher_manager.h eap/eap.h pen/pen.h ipsec/ipsec_types.h \ +@USE_DEV_HEADERS_TRUE@plugins/plugin_loader.h plugins/plugin.h plugins/plugin_feature.h \ +@USE_DEV_HEADERS_TRUE@processing/jobs/job.h processing/jobs/callback_job.h processing/processor.h \ +@USE_DEV_HEADERS_TRUE@processing/scheduler.h selectors/traffic_selector.h \ +@USE_DEV_HEADERS_TRUE@threading/thread.h threading/thread_value.h \ +@USE_DEV_HEADERS_TRUE@threading/mutex.h threading/condvar.h threading/spinlock.h threading/semaphore.h \ +@USE_DEV_HEADERS_TRUE@threading/rwlock.h threading/rwlock_condvar.h threading/lock_profiler.h \ +@USE_DEV_HEADERS_TRUE@utils.h utils/host.h utils/packet.h utils/identification.h utils/lexparser.h \ +@USE_DEV_HEADERS_TRUE@utils/linked_list.h utils/blocking_queue.h utils/hashtable.h utils/enumerator.h \ +@USE_DEV_HEADERS_TRUE@utils/optionsfrom.h utils/capabilities.h utils/backtrace.h utils/tun_device.h \ +@USE_DEV_HEADERS_TRUE@utils/leak_detective.h integrity_checker.h + libstrongswan_la_LIBADD = $(PTHREADLIB) $(DLLIB) $(BTLIB) $(SOCKLIB) \ - $(RTLIB) $(am__append_6) $(am__append_8) $(am__append_10) \ - $(am__append_12) $(am__append_14) $(am__append_16) \ - $(am__append_18) $(am__append_20) $(am__append_22) \ - $(am__append_24) $(am__append_26) $(am__append_28) \ - $(am__append_30) $(am__append_32) $(am__append_34) \ - $(am__append_36) $(am__append_38) $(am__append_40) \ - $(am__append_42) $(am__append_44) $(am__append_46) \ - $(am__append_48) $(am__append_50) $(am__append_52) \ - $(am__append_54) $(am__append_56) $(am__append_58) \ - $(am__append_60) $(am__append_62) $(am__append_64) \ - $(am__append_66) $(am__append_68) $(am__append_70) \ - $(am__append_72) $(am__append_74) $(am__append_76) \ - $(am__append_78) $(am__append_80) + $(RTLIB) $(BFDLIB) $(am__append_6) $(am__append_7) \ + $(am__append_9) $(am__append_11) $(am__append_13) \ + $(am__append_15) $(am__append_17) $(am__append_19) \ + $(am__append_21) $(am__append_23) $(am__append_25) \ + $(am__append_27) $(am__append_29) $(am__append_31) \ + $(am__append_33) $(am__append_35) $(am__append_37) \ + $(am__append_39) $(am__append_41) $(am__append_43) \ + $(am__append_45) $(am__append_47) $(am__append_49) \ + $(am__append_51) $(am__append_53) $(am__append_55) \ + $(am__append_57) $(am__append_59) $(am__append_61) \ + $(am__append_63) $(am__append_65) $(am__append_67) \ + $(am__append_69) $(am__append_71) $(am__append_73) \ + $(am__append_75) $(am__append_77) $(am__append_79) \ + $(am__append_81) $(am__append_83) INCLUDES = -I$(top_srcdir)/src/libstrongswan AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" \ -DIPSEC_LIB_DIR=\"${ipseclibdir}\" \ @@ -601,58 +629,58 @@ AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" \ $(am__append_3) $(am__append_4) EXTRA_DIST = \ asn1/oid.txt asn1/oid.pl \ -crypto/proposal/proposal_keywords.txt \ +crypto/proposal/proposal_keywords_static.txt \ Android.mk AndroidConfigLocal.h BUILT_SOURCES = \ $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \ -$(srcdir)/crypto/proposal/proposal_keywords.c +$(srcdir)/crypto/proposal/proposal_keywords_static.c MAINTAINERCLEANFILES = \ $(srcdir)/asn1/oid.c $(srcdir)/asn1/oid.h \ -$(srcdir)/crypto/proposal/proposal_keywords.c - -@MONOLITHIC_FALSE@SUBDIRS = . $(am__append_7) $(am__append_9) \ -@MONOLITHIC_FALSE@ $(am__append_11) $(am__append_13) \ -@MONOLITHIC_FALSE@ $(am__append_15) $(am__append_17) \ -@MONOLITHIC_FALSE@ $(am__append_19) $(am__append_21) \ -@MONOLITHIC_FALSE@ $(am__append_23) $(am__append_25) \ -@MONOLITHIC_FALSE@ $(am__append_27) $(am__append_29) \ -@MONOLITHIC_FALSE@ $(am__append_31) $(am__append_33) \ -@MONOLITHIC_FALSE@ $(am__append_35) $(am__append_37) \ -@MONOLITHIC_FALSE@ $(am__append_39) $(am__append_41) \ -@MONOLITHIC_FALSE@ $(am__append_43) $(am__append_45) \ -@MONOLITHIC_FALSE@ $(am__append_47) $(am__append_49) \ -@MONOLITHIC_FALSE@ $(am__append_51) $(am__append_53) \ -@MONOLITHIC_FALSE@ $(am__append_55) $(am__append_57) \ -@MONOLITHIC_FALSE@ $(am__append_59) $(am__append_61) \ -@MONOLITHIC_FALSE@ $(am__append_63) $(am__append_65) \ -@MONOLITHIC_FALSE@ $(am__append_67) $(am__append_69) \ -@MONOLITHIC_FALSE@ $(am__append_71) $(am__append_73) \ -@MONOLITHIC_FALSE@ $(am__append_75) $(am__append_77) \ -@MONOLITHIC_FALSE@ $(am__append_79) +$(srcdir)/crypto/proposal/proposal_keywords_static.c + +@MONOLITHIC_FALSE@SUBDIRS = . $(am__append_8) $(am__append_10) \ +@MONOLITHIC_FALSE@ $(am__append_12) $(am__append_14) \ +@MONOLITHIC_FALSE@ $(am__append_16) $(am__append_18) \ +@MONOLITHIC_FALSE@ $(am__append_20) $(am__append_22) \ +@MONOLITHIC_FALSE@ $(am__append_24) $(am__append_26) \ +@MONOLITHIC_FALSE@ $(am__append_28) $(am__append_30) \ +@MONOLITHIC_FALSE@ $(am__append_32) $(am__append_34) \ +@MONOLITHIC_FALSE@ $(am__append_36) $(am__append_38) \ +@MONOLITHIC_FALSE@ $(am__append_40) $(am__append_42) \ +@MONOLITHIC_FALSE@ $(am__append_44) $(am__append_46) \ +@MONOLITHIC_FALSE@ $(am__append_48) $(am__append_50) \ +@MONOLITHIC_FALSE@ $(am__append_52) $(am__append_54) \ +@MONOLITHIC_FALSE@ $(am__append_56) $(am__append_58) \ +@MONOLITHIC_FALSE@ $(am__append_60) $(am__append_62) \ +@MONOLITHIC_FALSE@ $(am__append_64) $(am__append_66) \ +@MONOLITHIC_FALSE@ $(am__append_68) $(am__append_70) \ +@MONOLITHIC_FALSE@ $(am__append_72) $(am__append_74) \ +@MONOLITHIC_FALSE@ $(am__append_76) $(am__append_78) \ +@MONOLITHIC_FALSE@ $(am__append_80) $(am__append_82) # build plugins with their own Makefile ####################################### -@MONOLITHIC_TRUE@SUBDIRS = $(am__append_7) $(am__append_9) \ -@MONOLITHIC_TRUE@ $(am__append_11) $(am__append_13) \ -@MONOLITHIC_TRUE@ $(am__append_15) $(am__append_17) \ -@MONOLITHIC_TRUE@ $(am__append_19) $(am__append_21) \ -@MONOLITHIC_TRUE@ $(am__append_23) $(am__append_25) \ -@MONOLITHIC_TRUE@ $(am__append_27) $(am__append_29) \ -@MONOLITHIC_TRUE@ $(am__append_31) $(am__append_33) \ -@MONOLITHIC_TRUE@ $(am__append_35) $(am__append_37) \ -@MONOLITHIC_TRUE@ $(am__append_39) $(am__append_41) \ -@MONOLITHIC_TRUE@ $(am__append_43) $(am__append_45) \ -@MONOLITHIC_TRUE@ $(am__append_47) $(am__append_49) \ -@MONOLITHIC_TRUE@ $(am__append_51) $(am__append_53) \ -@MONOLITHIC_TRUE@ $(am__append_55) $(am__append_57) \ -@MONOLITHIC_TRUE@ $(am__append_59) $(am__append_61) \ -@MONOLITHIC_TRUE@ $(am__append_63) $(am__append_65) \ -@MONOLITHIC_TRUE@ $(am__append_67) $(am__append_69) \ -@MONOLITHIC_TRUE@ $(am__append_71) $(am__append_73) \ -@MONOLITHIC_TRUE@ $(am__append_75) $(am__append_77) \ -@MONOLITHIC_TRUE@ $(am__append_79) +@MONOLITHIC_TRUE@SUBDIRS = $(am__append_8) $(am__append_10) \ +@MONOLITHIC_TRUE@ $(am__append_12) $(am__append_14) \ +@MONOLITHIC_TRUE@ $(am__append_16) $(am__append_18) \ +@MONOLITHIC_TRUE@ $(am__append_20) $(am__append_22) \ +@MONOLITHIC_TRUE@ $(am__append_24) $(am__append_26) \ +@MONOLITHIC_TRUE@ $(am__append_28) $(am__append_30) \ +@MONOLITHIC_TRUE@ $(am__append_32) $(am__append_34) \ +@MONOLITHIC_TRUE@ $(am__append_36) $(am__append_38) \ +@MONOLITHIC_TRUE@ $(am__append_40) $(am__append_42) \ +@MONOLITHIC_TRUE@ $(am__append_44) $(am__append_46) \ +@MONOLITHIC_TRUE@ $(am__append_48) $(am__append_50) \ +@MONOLITHIC_TRUE@ $(am__append_52) $(am__append_54) \ +@MONOLITHIC_TRUE@ $(am__append_56) $(am__append_58) \ +@MONOLITHIC_TRUE@ $(am__append_60) $(am__append_62) \ +@MONOLITHIC_TRUE@ $(am__append_64) $(am__append_66) \ +@MONOLITHIC_TRUE@ $(am__append_68) $(am__append_70) \ +@MONOLITHIC_TRUE@ $(am__append_72) $(am__append_74) \ +@MONOLITHIC_TRUE@ $(am__append_76) $(am__append_78) \ +@MONOLITHIC_TRUE@ $(am__append_80) $(am__append_82) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -736,9 +764,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backtrace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bio_reader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bio_writer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blocking_queue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builder.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback_cred.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback_job.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/capabilities.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cert_cache.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certificate.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chunk.Plo@am__quote@ @@ -764,18 +794,23 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/identification.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ietf_attributes.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/integrity_checker.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/leak_detective.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexparser.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/library.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linked_list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac_prf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac_signer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_cred.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mutex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp_response.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp_response_wrapper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oid.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optionsfrom.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pen.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs7.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs9.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_feature.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_loader.Plo@am__quote@ @@ -785,17 +820,21 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/private_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/processor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_keywords.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_keywords_static.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/public_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rng.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rwlock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/semaphore.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/settings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shared_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spinlock.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_value.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tun_device.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ .c.o: @@ -868,6 +907,13 @@ hasher.lo: crypto/hashers/hasher.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o hasher.lo `test -f 'crypto/hashers/hasher.c' || echo '$(srcdir)/'`crypto/hashers/hasher.c +pkcs7.lo: crypto/pkcs7.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pkcs7.lo -MD -MP -MF $(DEPDIR)/pkcs7.Tpo -c -o pkcs7.lo `test -f 'crypto/pkcs7.c' || echo '$(srcdir)/'`crypto/pkcs7.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pkcs7.Tpo $(DEPDIR)/pkcs7.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/pkcs7.c' object='pkcs7.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o pkcs7.lo `test -f 'crypto/pkcs7.c' || echo '$(srcdir)/'`crypto/pkcs7.c + pkcs9.lo: crypto/pkcs9.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pkcs9.lo -MD -MP -MF $(DEPDIR)/pkcs9.Tpo -c -o pkcs9.lo `test -f 'crypto/pkcs9.c' || echo '$(srcdir)/'`crypto/pkcs9.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pkcs9.Tpo $(DEPDIR)/pkcs9.Plo @@ -882,6 +928,13 @@ proposal_keywords.lo: crypto/proposal/proposal_keywords.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal_keywords.lo `test -f 'crypto/proposal/proposal_keywords.c' || echo '$(srcdir)/'`crypto/proposal/proposal_keywords.c +proposal_keywords_static.lo: crypto/proposal/proposal_keywords_static.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT proposal_keywords_static.lo -MD -MP -MF $(DEPDIR)/proposal_keywords_static.Tpo -c -o proposal_keywords_static.lo `test -f 'crypto/proposal/proposal_keywords_static.c' || echo '$(srcdir)/'`crypto/proposal/proposal_keywords_static.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/proposal_keywords_static.Tpo $(DEPDIR)/proposal_keywords_static.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/proposal/proposal_keywords_static.c' object='proposal_keywords_static.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o proposal_keywords_static.lo `test -f 'crypto/proposal/proposal_keywords_static.c' || echo '$(srcdir)/'`crypto/proposal/proposal_keywords_static.c + prf.lo: crypto/prfs/prf.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT prf.lo -MD -MP -MF $(DEPDIR)/prf.Tpo -c -o prf.lo `test -f 'crypto/prfs/prf.c' || echo '$(srcdir)/'`crypto/prfs/prf.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/prf.Tpo $(DEPDIR)/prf.Plo @@ -889,6 +942,13 @@ prf.lo: crypto/prfs/prf.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o prf.lo `test -f 'crypto/prfs/prf.c' || echo '$(srcdir)/'`crypto/prfs/prf.c +mac_prf.lo: crypto/prfs/mac_prf.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mac_prf.lo -MD -MP -MF $(DEPDIR)/mac_prf.Tpo -c -o mac_prf.lo `test -f 'crypto/prfs/mac_prf.c' || echo '$(srcdir)/'`crypto/prfs/mac_prf.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mac_prf.Tpo $(DEPDIR)/mac_prf.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/prfs/mac_prf.c' object='mac_prf.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mac_prf.lo `test -f 'crypto/prfs/mac_prf.c' || echo '$(srcdir)/'`crypto/prfs/mac_prf.c + rng.lo: crypto/rngs/rng.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rng.lo -MD -MP -MF $(DEPDIR)/rng.Tpo -c -o rng.lo `test -f 'crypto/rngs/rng.c' || echo '$(srcdir)/'`crypto/rngs/rng.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rng.Tpo $(DEPDIR)/rng.Plo @@ -910,6 +970,13 @@ signer.lo: crypto/signers/signer.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o signer.lo `test -f 'crypto/signers/signer.c' || echo '$(srcdir)/'`crypto/signers/signer.c +mac_signer.lo: crypto/signers/mac_signer.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mac_signer.lo -MD -MP -MF $(DEPDIR)/mac_signer.Tpo -c -o mac_signer.lo `test -f 'crypto/signers/mac_signer.c' || echo '$(srcdir)/'`crypto/signers/mac_signer.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/mac_signer.Tpo $(DEPDIR)/mac_signer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto/signers/mac_signer.c' object='mac_signer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mac_signer.lo `test -f 'crypto/signers/mac_signer.c' || echo '$(srcdir)/'`crypto/signers/mac_signer.c + crypto_factory.lo: crypto/crypto_factory.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT crypto_factory.lo -MD -MP -MF $(DEPDIR)/crypto_factory.Tpo -c -o crypto_factory.lo `test -f 'crypto/crypto_factory.c' || echo '$(srcdir)/'`crypto/crypto_factory.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/crypto_factory.Tpo $(DEPDIR)/crypto_factory.Plo @@ -1099,6 +1166,13 @@ eap.lo: eap/eap.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o eap.lo `test -f 'eap/eap.c' || echo '$(srcdir)/'`eap/eap.c +ipsec_types.lo: ipsec/ipsec_types.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ipsec_types.lo -MD -MP -MF $(DEPDIR)/ipsec_types.Tpo -c -o ipsec_types.lo `test -f 'ipsec/ipsec_types.c' || echo '$(srcdir)/'`ipsec/ipsec_types.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/ipsec_types.Tpo $(DEPDIR)/ipsec_types.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ipsec/ipsec_types.c' object='ipsec_types.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ipsec_types.lo `test -f 'ipsec/ipsec_types.c' || echo '$(srcdir)/'`ipsec/ipsec_types.c + pen.lo: pen/pen.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT pen.lo -MD -MP -MF $(DEPDIR)/pen.Tpo -c -o pen.lo `test -f 'pen/pen.c' || echo '$(srcdir)/'`pen/pen.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/pen.Tpo $(DEPDIR)/pen.Plo @@ -1176,6 +1250,13 @@ mutex.lo: threading/mutex.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o mutex.lo `test -f 'threading/mutex.c' || echo '$(srcdir)/'`threading/mutex.c +semaphore.lo: threading/semaphore.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT semaphore.lo -MD -MP -MF $(DEPDIR)/semaphore.Tpo -c -o semaphore.lo `test -f 'threading/semaphore.c' || echo '$(srcdir)/'`threading/semaphore.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/semaphore.Tpo $(DEPDIR)/semaphore.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threading/semaphore.c' object='semaphore.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o semaphore.lo `test -f 'threading/semaphore.c' || echo '$(srcdir)/'`threading/semaphore.c + rwlock.lo: threading/rwlock.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rwlock.lo -MD -MP -MF $(DEPDIR)/rwlock.Tpo -c -o rwlock.lo `test -f 'threading/rwlock.c' || echo '$(srcdir)/'`threading/rwlock.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/rwlock.Tpo $(DEPDIR)/rwlock.Plo @@ -1183,6 +1264,13 @@ rwlock.lo: threading/rwlock.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rwlock.lo `test -f 'threading/rwlock.c' || echo '$(srcdir)/'`threading/rwlock.c +spinlock.lo: threading/spinlock.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT spinlock.lo -MD -MP -MF $(DEPDIR)/spinlock.Tpo -c -o spinlock.lo `test -f 'threading/spinlock.c' || echo '$(srcdir)/'`threading/spinlock.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/spinlock.Tpo $(DEPDIR)/spinlock.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='threading/spinlock.c' object='spinlock.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o spinlock.lo `test -f 'threading/spinlock.c' || echo '$(srcdir)/'`threading/spinlock.c + host.lo: utils/host.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT host.lo -MD -MP -MF $(DEPDIR)/host.Tpo -c -o host.lo `test -f 'utils/host.c' || echo '$(srcdir)/'`utils/host.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/host.Tpo $(DEPDIR)/host.Plo @@ -1190,6 +1278,13 @@ host.lo: utils/host.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o host.lo `test -f 'utils/host.c' || echo '$(srcdir)/'`utils/host.c +packet.lo: utils/packet.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT packet.lo -MD -MP -MF $(DEPDIR)/packet.Tpo -c -o packet.lo `test -f 'utils/packet.c' || echo '$(srcdir)/'`utils/packet.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/packet.Tpo $(DEPDIR)/packet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/packet.c' object='packet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o packet.lo `test -f 'utils/packet.c' || echo '$(srcdir)/'`utils/packet.c + identification.lo: utils/identification.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT identification.lo -MD -MP -MF $(DEPDIR)/identification.Tpo -c -o identification.lo `test -f 'utils/identification.c' || echo '$(srcdir)/'`utils/identification.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/identification.Tpo $(DEPDIR)/identification.Plo @@ -1211,6 +1306,13 @@ linked_list.lo: utils/linked_list.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o linked_list.lo `test -f 'utils/linked_list.c' || echo '$(srcdir)/'`utils/linked_list.c +blocking_queue.lo: utils/blocking_queue.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT blocking_queue.lo -MD -MP -MF $(DEPDIR)/blocking_queue.Tpo -c -o blocking_queue.lo `test -f 'utils/blocking_queue.c' || echo '$(srcdir)/'`utils/blocking_queue.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/blocking_queue.Tpo $(DEPDIR)/blocking_queue.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/blocking_queue.c' object='blocking_queue.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o blocking_queue.lo `test -f 'utils/blocking_queue.c' || echo '$(srcdir)/'`utils/blocking_queue.c + hashtable.lo: utils/hashtable.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT hashtable.lo -MD -MP -MF $(DEPDIR)/hashtable.Tpo -c -o hashtable.lo `test -f 'utils/hashtable.c' || echo '$(srcdir)/'`utils/hashtable.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/hashtable.Tpo $(DEPDIR)/hashtable.Plo @@ -1232,6 +1334,13 @@ optionsfrom.lo: utils/optionsfrom.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o optionsfrom.lo `test -f 'utils/optionsfrom.c' || echo '$(srcdir)/'`utils/optionsfrom.c +capabilities.lo: utils/capabilities.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT capabilities.lo -MD -MP -MF $(DEPDIR)/capabilities.Tpo -c -o capabilities.lo `test -f 'utils/capabilities.c' || echo '$(srcdir)/'`utils/capabilities.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/capabilities.Tpo $(DEPDIR)/capabilities.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/capabilities.c' object='capabilities.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o capabilities.lo `test -f 'utils/capabilities.c' || echo '$(srcdir)/'`utils/capabilities.c + backtrace.lo: utils/backtrace.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT backtrace.lo -MD -MP -MF $(DEPDIR)/backtrace.Tpo -c -o backtrace.lo `test -f 'utils/backtrace.c' || echo '$(srcdir)/'`utils/backtrace.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/backtrace.Tpo $(DEPDIR)/backtrace.Plo @@ -1239,6 +1348,13 @@ backtrace.lo: utils/backtrace.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o backtrace.lo `test -f 'utils/backtrace.c' || echo '$(srcdir)/'`utils/backtrace.c +tun_device.lo: utils/tun_device.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tun_device.lo -MD -MP -MF $(DEPDIR)/tun_device.Tpo -c -o tun_device.lo `test -f 'utils/tun_device.c' || echo '$(srcdir)/'`utils/tun_device.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/tun_device.Tpo $(DEPDIR)/tun_device.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='utils/tun_device.c' object='tun_device.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tun_device.lo `test -f 'utils/tun_device.c' || echo '$(srcdir)/'`utils/tun_device.c + leak_detective.lo: utils/leak_detective.c @am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT leak_detective.lo -MD -MP -MF $(DEPDIR)/leak_detective.Tpo -c -o leak_detective.lo `test -f 'utils/leak_detective.c' || echo '$(srcdir)/'`utils/leak_detective.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/leak_detective.Tpo $(DEPDIR)/leak_detective.Plo @@ -1251,6 +1367,29 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs +install-nobase_strongswan_includeHEADERS: $(nobase_strongswan_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(strongswan_includedir)" || $(MKDIR_P) "$(DESTDIR)$(strongswan_includedir)" + @list='$(nobase_strongswan_include_HEADERS)'; test -n "$(strongswan_includedir)" || list=; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo "$(MKDIR_P) '$(DESTDIR)$(strongswan_includedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(strongswan_includedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(strongswan_includedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(strongswan_includedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_strongswan_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_strongswan_include_HEADERS)'; test -n "$(strongswan_includedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(strongswan_includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(strongswan_includedir)" && rm -f $$files # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -1448,10 +1587,10 @@ distdir: $(DISTFILES) check-am: all-am check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-recursive -all-am: Makefile $(LTLIBRARIES) +all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(ipseclibdir)"; do \ + for dir in "$(DESTDIR)$(ipseclibdir)" "$(DESTDIR)$(strongswan_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) @@ -1505,7 +1644,8 @@ info: info-recursive info-am: -install-data-am: install-ipseclibLTLIBRARIES +install-data-am: install-ipseclibLTLIBRARIES \ + install-nobase_strongswan_includeHEADERS install-dvi: install-dvi-recursive @@ -1551,7 +1691,8 @@ ps: ps-recursive ps-am: -uninstall-am: uninstall-ipseclibLTLIBRARIES +uninstall-am: uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_strongswan_includeHEADERS .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \ ctags-recursive install install-am install-strip \ @@ -1566,12 +1707,14 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-ipseclibLTLIBRARIES install-man \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ - uninstall uninstall-am uninstall-ipseclibLTLIBRARIES + install-nobase_strongswan_includeHEADERS install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_strongswan_includeHEADERS library.lo : $(top_builddir)/config.status @@ -1582,10 +1725,10 @@ $(srcdir)/asn1/oid.c : $(srcdir)/asn1/oid.pl $(srcdir)/asn1/oid.txt $(srcdir)/asn1/oid.h : $(srcdir)/asn1/oid.pl $(srcdir)/asn1/oid.txt (cd $(srcdir)/asn1/ && $(PERL) oid.pl) -$(srcdir)/crypto/proposal/proposal_keywords.c: $(srcdir)/crypto/proposal/proposal_keywords.txt \ - $(srcdir)/crypto/proposal/proposal_keywords.h - $(GPERF) -N proposal_get_token -m 10 -C -G -c -t -D < \ - $(srcdir)/crypto/proposal/proposal_keywords.txt > $@ +$(srcdir)/crypto/proposal/proposal_keywords_static.c: $(srcdir)/crypto/proposal/proposal_keywords_static.txt \ + $(srcdir)/crypto/proposal/proposal_keywords_static.h + $(GPERF) -N proposal_get_token_static -m 10 -C -G -c -t -D < \ + $(srcdir)/crypto/proposal/proposal_keywords_static.txt > $@ # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c index 4cb38d126..c9f6fce25 100644 --- a/src/libstrongswan/asn1/asn1.c +++ b/src/libstrongswan/asn1/asn1.c @@ -28,7 +28,7 @@ /** * Commonly used ASN1 values. */ -const chunk_t ASN1_INTEGER_0 = chunk_from_chars(0x02, 0x00); +const chunk_t ASN1_INTEGER_0 = chunk_from_chars(0x02, 0x01, 0x00); const chunk_t ASN1_INTEGER_1 = chunk_from_chars(0x02, 0x01, 0x01); const chunk_t ASN1_INTEGER_2 = chunk_from_chars(0x02, 0x01, 0x02); @@ -228,7 +228,8 @@ size_t asn1_length(chunk_t *blob) /* read length field, skip tag and length */ n = blob->ptr[1]; - *blob = chunk_skip(*blob, 2); + blob->ptr += 2; + blob->len -= 2; if ((n & 0x80) == 0) { /* single length octet */ @@ -760,16 +761,13 @@ chunk_t asn1_integer(const char *mode, chunk_t content) size_t len; u_char *pos; - if (content.len == 0 || (content.len == 1 && *content.ptr == 0x00)) - { - /* a zero ASN.1 integer does not have a value field */ - len = 0; - } - else - { - /* ASN.1 integers must be positive numbers in two's complement */ - len = content.len + ((*content.ptr & 0x80) ? 1 : 0); + if (content.len == 0) + { /* make sure 0 is encoded properly */ + content = chunk_from_chars(0x00); } + + /* ASN.1 integers must be positive numbers in two's complement */ + len = content.len + ((*content.ptr & 0x80) ? 1 : 0); pos = asn1_build_object(&object, ASN1_INTEGER, len); if (len > content.len) { diff --git a/src/libstrongswan/asn1/oid.c b/src/libstrongswan/asn1/oid.c index bfc985c25..b21299620 100644 --- a/src/libstrongswan/asn1/oid.c +++ b/src/libstrongswan/asn1/oid.c @@ -179,8 +179,8 @@ const oid_t oid_names[] = { { 0x02, 167, 0, 7, "ecdsa-with-SHA256" }, /* 166 */ { 0x03, 168, 0, 7, "ecdsa-with-SHA384" }, /* 167 */ { 0x04, 0, 0, 7, "ecdsa-with-SHA512" }, /* 168 */ - {0x2B, 320, 1, 0, "" }, /* 169 */ - { 0x06, 234, 1, 1, "dod" }, /* 170 */ + {0x2B, 323, 1, 0, "" }, /* 169 */ + { 0x06, 237, 1, 1, "dod" }, /* 170 */ { 0x01, 0, 1, 2, "internet" }, /* 171 */ { 0x04, 194, 1, 3, "private" }, /* 172 */ { 0x01, 0, 1, 4, "enterprise" }, /* 173 */ @@ -206,7 +206,7 @@ const oid_t oid_names[] = { { 0x4B, 0, 0, 11, "TCGID" }, /* 193 */ { 0x05, 0, 1, 3, "security" }, /* 194 */ { 0x05, 0, 1, 4, "mechanisms" }, /* 195 */ - { 0x07, 0, 1, 5, "id-pkix" }, /* 196 */ + { 0x07, 234, 1, 5, "id-pkix" }, /* 196 */ { 0x01, 201, 1, 6, "id-pe" }, /* 197 */ { 0x01, 199, 0, 7, "authorityInfoAccess" }, /* 198 */ { 0x03, 200, 0, 7, "qcStatements" }, /* 199 */ @@ -244,144 +244,147 @@ const oid_t oid_names[] = { { 0x02, 232, 0, 7, "caIssuers" }, /* 231 */ { 0x03, 233, 0, 7, "timeStamping" }, /* 232 */ { 0x05, 0, 0, 7, "caRepository" }, /* 233 */ - { 0x0E, 240, 1, 1, "oiw" }, /* 234 */ - { 0x03, 0, 1, 2, "secsig" }, /* 235 */ - { 0x02, 0, 1, 3, "algorithms" }, /* 236 */ - { 0x07, 238, 0, 4, "des-cbc" }, /* 237 */ - { 0x1A, 239, 0, 4, "sha-1" }, /* 238 */ - { 0x1D, 0, 0, 4, "sha-1WithRSASignature" }, /* 239 */ - { 0x24, 286, 1, 1, "TeleTrusT" }, /* 240 */ - { 0x03, 0, 1, 2, "algorithm" }, /* 241 */ - { 0x03, 0, 1, 3, "signatureAlgorithm" }, /* 242 */ - { 0x01, 247, 1, 4, "rsaSignature" }, /* 243 */ - { 0x02, 245, 0, 5, "rsaSigWithripemd160" }, /* 244 */ - { 0x03, 246, 0, 5, "rsaSigWithripemd128" }, /* 245 */ - { 0x04, 0, 0, 5, "rsaSigWithripemd256" }, /* 246 */ - { 0x02, 0, 1, 4, "ecSign" }, /* 247 */ - { 0x01, 249, 0, 5, "ecSignWithsha1" }, /* 248 */ - { 0x02, 250, 0, 5, "ecSignWithripemd160" }, /* 249 */ - { 0x03, 251, 0, 5, "ecSignWithmd2" }, /* 250 */ - { 0x04, 252, 0, 5, "ecSignWithmd5" }, /* 251 */ - { 0x05, 269, 1, 5, "ttt-ecg" }, /* 252 */ - { 0x01, 257, 1, 6, "fieldType" }, /* 253 */ - { 0x01, 0, 1, 7, "characteristictwoField" }, /* 254 */ - { 0x01, 0, 1, 8, "basisType" }, /* 255 */ - { 0x01, 0, 0, 9, "ipBasis" }, /* 256 */ - { 0x02, 259, 1, 6, "keyType" }, /* 257 */ - { 0x01, 0, 0, 7, "ecgPublicKey" }, /* 258 */ - { 0x03, 260, 0, 6, "curve" }, /* 259 */ - { 0x04, 267, 1, 6, "signatures" }, /* 260 */ - { 0x01, 262, 0, 7, "ecgdsa-with-RIPEMD160" }, /* 261 */ - { 0x02, 263, 0, 7, "ecgdsa-with-SHA1" }, /* 262 */ - { 0x03, 264, 0, 7, "ecgdsa-with-SHA224" }, /* 263 */ - { 0x04, 265, 0, 7, "ecgdsa-with-SHA256" }, /* 264 */ - { 0x05, 266, 0, 7, "ecgdsa-with-SHA384" }, /* 265 */ - { 0x06, 0, 0, 7, "ecgdsa-with-SHA512" }, /* 266 */ - { 0x05, 0, 1, 6, "module" }, /* 267 */ - { 0x01, 0, 0, 7, "1" }, /* 268 */ - { 0x08, 0, 1, 5, "ecStdCurvesAndGeneration" }, /* 269 */ - { 0x01, 0, 1, 6, "ellipticCurve" }, /* 270 */ - { 0x01, 0, 1, 7, "versionOne" }, /* 271 */ - { 0x01, 273, 0, 8, "brainpoolP160r1" }, /* 272 */ - { 0x02, 274, 0, 8, "brainpoolP160t1" }, /* 273 */ - { 0x03, 275, 0, 8, "brainpoolP192r1" }, /* 274 */ - { 0x04, 276, 0, 8, "brainpoolP192t1" }, /* 275 */ - { 0x05, 277, 0, 8, "brainpoolP224r1" }, /* 276 */ - { 0x06, 278, 0, 8, "brainpoolP224t1" }, /* 277 */ - { 0x07, 279, 0, 8, "brainpoolP256r1" }, /* 278 */ - { 0x08, 280, 0, 8, "brainpoolP256t1" }, /* 279 */ - { 0x09, 281, 0, 8, "brainpoolP320r1" }, /* 280 */ - { 0x0A, 282, 0, 8, "brainpoolP320t1" }, /* 281 */ - { 0x0B, 283, 0, 8, "brainpoolP384r1" }, /* 282 */ - { 0x0C, 284, 0, 8, "brainpoolP384t1" }, /* 283 */ - { 0x0D, 285, 0, 8, "brainpoolP512r1" }, /* 284 */ - { 0x0E, 0, 0, 8, "brainpoolP512t1" }, /* 285 */ - { 0x81, 0, 1, 1, "" }, /* 286 */ - { 0x04, 0, 1, 2, "Certicom" }, /* 287 */ - { 0x00, 0, 1, 3, "curve" }, /* 288 */ - { 0x01, 290, 0, 4, "sect163k1" }, /* 289 */ - { 0x02, 291, 0, 4, "sect163r1" }, /* 290 */ - { 0x03, 292, 0, 4, "sect239k1" }, /* 291 */ - { 0x04, 293, 0, 4, "sect113r1" }, /* 292 */ - { 0x05, 294, 0, 4, "sect113r2" }, /* 293 */ - { 0x06, 295, 0, 4, "secp112r1" }, /* 294 */ - { 0x07, 296, 0, 4, "secp112r2" }, /* 295 */ - { 0x08, 297, 0, 4, "secp160r1" }, /* 296 */ - { 0x09, 298, 0, 4, "secp160k1" }, /* 297 */ - { 0x0A, 299, 0, 4, "secp256k1" }, /* 298 */ - { 0x0F, 300, 0, 4, "sect163r2" }, /* 299 */ - { 0x10, 301, 0, 4, "sect283k1" }, /* 300 */ - { 0x11, 302, 0, 4, "sect283r1" }, /* 301 */ - { 0x16, 303, 0, 4, "sect131r1" }, /* 302 */ - { 0x17, 304, 0, 4, "sect131r2" }, /* 303 */ - { 0x18, 305, 0, 4, "sect193r1" }, /* 304 */ - { 0x19, 306, 0, 4, "sect193r2" }, /* 305 */ - { 0x1A, 307, 0, 4, "sect233k1" }, /* 306 */ - { 0x1B, 308, 0, 4, "sect233r1" }, /* 307 */ - { 0x1C, 309, 0, 4, "secp128r1" }, /* 308 */ - { 0x1D, 310, 0, 4, "secp128r2" }, /* 309 */ - { 0x1E, 311, 0, 4, "secp160r2" }, /* 310 */ - { 0x1F, 312, 0, 4, "secp192k1" }, /* 311 */ - { 0x20, 313, 0, 4, "secp224k1" }, /* 312 */ - { 0x21, 314, 0, 4, "secp224r1" }, /* 313 */ - { 0x22, 315, 0, 4, "secp384r1" }, /* 314 */ - { 0x23, 316, 0, 4, "secp521r1" }, /* 315 */ - { 0x24, 317, 0, 4, "sect409k1" }, /* 316 */ - { 0x25, 318, 0, 4, "sect409r1" }, /* 317 */ - { 0x26, 319, 0, 4, "sect571k1" }, /* 318 */ - { 0x27, 0, 0, 4, "sect571r1" }, /* 319 */ - {0x60, 366, 1, 0, "" }, /* 320 */ - { 0x86, 0, 1, 1, "" }, /* 321 */ - { 0x48, 0, 1, 2, "" }, /* 322 */ - { 0x01, 0, 1, 3, "organization" }, /* 323 */ - { 0x65, 342, 1, 4, "gov" }, /* 324 */ - { 0x03, 0, 1, 5, "csor" }, /* 325 */ - { 0x04, 0, 1, 6, "nistalgorithm" }, /* 326 */ - { 0x01, 337, 1, 7, "aes" }, /* 327 */ - { 0x02, 329, 0, 8, "id-aes128-CBC" }, /* 328 */ - { 0x06, 330, 0, 8, "id-aes128-GCM" }, /* 329 */ - { 0x07, 331, 0, 8, "id-aes128-CCM" }, /* 330 */ - { 0x16, 332, 0, 8, "id-aes192-CBC" }, /* 331 */ - { 0x1A, 333, 0, 8, "id-aes192-GCM" }, /* 332 */ - { 0x1B, 334, 0, 8, "id-aes192-CCM" }, /* 333 */ - { 0x2A, 335, 0, 8, "id-aes256-CBC" }, /* 334 */ - { 0x2E, 336, 0, 8, "id-aes256-GCM" }, /* 335 */ - { 0x2F, 0, 0, 8, "id-aes256-CCM" }, /* 336 */ - { 0x02, 0, 1, 7, "hashalgs" }, /* 337 */ - { 0x01, 339, 0, 8, "id-SHA-256" }, /* 338 */ - { 0x02, 340, 0, 8, "id-SHA-384" }, /* 339 */ - { 0x03, 341, 0, 8, "id-SHA-512" }, /* 340 */ - { 0x04, 0, 0, 8, "id-SHA-224" }, /* 341 */ - { 0x86, 0, 1, 4, "" }, /* 342 */ - { 0xf8, 0, 1, 5, "" }, /* 343 */ - { 0x42, 356, 1, 6, "netscape" }, /* 344 */ - { 0x01, 351, 1, 7, "" }, /* 345 */ - { 0x01, 347, 0, 8, "nsCertType" }, /* 346 */ - { 0x03, 348, 0, 8, "nsRevocationUrl" }, /* 347 */ - { 0x04, 349, 0, 8, "nsCaRevocationUrl" }, /* 348 */ - { 0x08, 350, 0, 8, "nsCaPolicyUrl" }, /* 349 */ - { 0x0d, 0, 0, 8, "nsComment" }, /* 350 */ - { 0x03, 354, 1, 7, "directory" }, /* 351 */ - { 0x01, 0, 1, 8, "" }, /* 352 */ - { 0x03, 0, 0, 9, "employeeNumber" }, /* 353 */ - { 0x04, 0, 1, 7, "policy" }, /* 354 */ - { 0x01, 0, 0, 8, "nsSGC" }, /* 355 */ - { 0x45, 0, 1, 6, "verisign" }, /* 356 */ - { 0x01, 0, 1, 7, "pki" }, /* 357 */ - { 0x09, 0, 1, 8, "attributes" }, /* 358 */ - { 0x02, 360, 0, 9, "messageType" }, /* 359 */ - { 0x03, 361, 0, 9, "pkiStatus" }, /* 360 */ - { 0x04, 362, 0, 9, "failInfo" }, /* 361 */ - { 0x05, 363, 0, 9, "senderNonce" }, /* 362 */ - { 0x06, 364, 0, 9, "recipientNonce" }, /* 363 */ - { 0x07, 365, 0, 9, "transID" }, /* 364 */ - { 0x08, 0, 0, 9, "extensionReq" }, /* 365 */ - {0x67, 0, 1, 0, "" }, /* 366 */ - { 0x81, 0, 1, 1, "" }, /* 367 */ - { 0x05, 0, 1, 2, "" }, /* 368 */ - { 0x02, 0, 1, 3, "tcg-attribute" }, /* 369 */ - { 0x01, 371, 0, 4, "tcg-at-tpmManufacturer" }, /* 370 */ - { 0x02, 372, 0, 4, "tcg-at-tpmModel" }, /* 371 */ - { 0x03, 373, 0, 4, "tcg-at-tpmVersion" }, /* 372 */ - { 0x0F, 0, 0, 4, "tcg-at-tpmIdLabel" } /* 373 */ + { 0x08, 0, 1, 5, "ipsec" }, /* 234 */ + { 0x02, 0, 1, 6, "certificate" }, /* 235 */ + { 0x02, 0, 0, 7, "iKEIntermediate" }, /* 236 */ + { 0x0E, 243, 1, 1, "oiw" }, /* 237 */ + { 0x03, 0, 1, 2, "secsig" }, /* 238 */ + { 0x02, 0, 1, 3, "algorithms" }, /* 239 */ + { 0x07, 241, 0, 4, "des-cbc" }, /* 240 */ + { 0x1A, 242, 0, 4, "sha-1" }, /* 241 */ + { 0x1D, 0, 0, 4, "sha-1WithRSASignature" }, /* 242 */ + { 0x24, 289, 1, 1, "TeleTrusT" }, /* 243 */ + { 0x03, 0, 1, 2, "algorithm" }, /* 244 */ + { 0x03, 0, 1, 3, "signatureAlgorithm" }, /* 245 */ + { 0x01, 250, 1, 4, "rsaSignature" }, /* 246 */ + { 0x02, 248, 0, 5, "rsaSigWithripemd160" }, /* 247 */ + { 0x03, 249, 0, 5, "rsaSigWithripemd128" }, /* 248 */ + { 0x04, 0, 0, 5, "rsaSigWithripemd256" }, /* 249 */ + { 0x02, 0, 1, 4, "ecSign" }, /* 250 */ + { 0x01, 252, 0, 5, "ecSignWithsha1" }, /* 251 */ + { 0x02, 253, 0, 5, "ecSignWithripemd160" }, /* 252 */ + { 0x03, 254, 0, 5, "ecSignWithmd2" }, /* 253 */ + { 0x04, 255, 0, 5, "ecSignWithmd5" }, /* 254 */ + { 0x05, 272, 1, 5, "ttt-ecg" }, /* 255 */ + { 0x01, 260, 1, 6, "fieldType" }, /* 256 */ + { 0x01, 0, 1, 7, "characteristictwoField" }, /* 257 */ + { 0x01, 0, 1, 8, "basisType" }, /* 258 */ + { 0x01, 0, 0, 9, "ipBasis" }, /* 259 */ + { 0x02, 262, 1, 6, "keyType" }, /* 260 */ + { 0x01, 0, 0, 7, "ecgPublicKey" }, /* 261 */ + { 0x03, 263, 0, 6, "curve" }, /* 262 */ + { 0x04, 270, 1, 6, "signatures" }, /* 263 */ + { 0x01, 265, 0, 7, "ecgdsa-with-RIPEMD160" }, /* 264 */ + { 0x02, 266, 0, 7, "ecgdsa-with-SHA1" }, /* 265 */ + { 0x03, 267, 0, 7, "ecgdsa-with-SHA224" }, /* 266 */ + { 0x04, 268, 0, 7, "ecgdsa-with-SHA256" }, /* 267 */ + { 0x05, 269, 0, 7, "ecgdsa-with-SHA384" }, /* 268 */ + { 0x06, 0, 0, 7, "ecgdsa-with-SHA512" }, /* 269 */ + { 0x05, 0, 1, 6, "module" }, /* 270 */ + { 0x01, 0, 0, 7, "1" }, /* 271 */ + { 0x08, 0, 1, 5, "ecStdCurvesAndGeneration" }, /* 272 */ + { 0x01, 0, 1, 6, "ellipticCurve" }, /* 273 */ + { 0x01, 0, 1, 7, "versionOne" }, /* 274 */ + { 0x01, 276, 0, 8, "brainpoolP160r1" }, /* 275 */ + { 0x02, 277, 0, 8, "brainpoolP160t1" }, /* 276 */ + { 0x03, 278, 0, 8, "brainpoolP192r1" }, /* 277 */ + { 0x04, 279, 0, 8, "brainpoolP192t1" }, /* 278 */ + { 0x05, 280, 0, 8, "brainpoolP224r1" }, /* 279 */ + { 0x06, 281, 0, 8, "brainpoolP224t1" }, /* 280 */ + { 0x07, 282, 0, 8, "brainpoolP256r1" }, /* 281 */ + { 0x08, 283, 0, 8, "brainpoolP256t1" }, /* 282 */ + { 0x09, 284, 0, 8, "brainpoolP320r1" }, /* 283 */ + { 0x0A, 285, 0, 8, "brainpoolP320t1" }, /* 284 */ + { 0x0B, 286, 0, 8, "brainpoolP384r1" }, /* 285 */ + { 0x0C, 287, 0, 8, "brainpoolP384t1" }, /* 286 */ + { 0x0D, 288, 0, 8, "brainpoolP512r1" }, /* 287 */ + { 0x0E, 0, 0, 8, "brainpoolP512t1" }, /* 288 */ + { 0x81, 0, 1, 1, "" }, /* 289 */ + { 0x04, 0, 1, 2, "Certicom" }, /* 290 */ + { 0x00, 0, 1, 3, "curve" }, /* 291 */ + { 0x01, 293, 0, 4, "sect163k1" }, /* 292 */ + { 0x02, 294, 0, 4, "sect163r1" }, /* 293 */ + { 0x03, 295, 0, 4, "sect239k1" }, /* 294 */ + { 0x04, 296, 0, 4, "sect113r1" }, /* 295 */ + { 0x05, 297, 0, 4, "sect113r2" }, /* 296 */ + { 0x06, 298, 0, 4, "secp112r1" }, /* 297 */ + { 0x07, 299, 0, 4, "secp112r2" }, /* 298 */ + { 0x08, 300, 0, 4, "secp160r1" }, /* 299 */ + { 0x09, 301, 0, 4, "secp160k1" }, /* 300 */ + { 0x0A, 302, 0, 4, "secp256k1" }, /* 301 */ + { 0x0F, 303, 0, 4, "sect163r2" }, /* 302 */ + { 0x10, 304, 0, 4, "sect283k1" }, /* 303 */ + { 0x11, 305, 0, 4, "sect283r1" }, /* 304 */ + { 0x16, 306, 0, 4, "sect131r1" }, /* 305 */ + { 0x17, 307, 0, 4, "sect131r2" }, /* 306 */ + { 0x18, 308, 0, 4, "sect193r1" }, /* 307 */ + { 0x19, 309, 0, 4, "sect193r2" }, /* 308 */ + { 0x1A, 310, 0, 4, "sect233k1" }, /* 309 */ + { 0x1B, 311, 0, 4, "sect233r1" }, /* 310 */ + { 0x1C, 312, 0, 4, "secp128r1" }, /* 311 */ + { 0x1D, 313, 0, 4, "secp128r2" }, /* 312 */ + { 0x1E, 314, 0, 4, "secp160r2" }, /* 313 */ + { 0x1F, 315, 0, 4, "secp192k1" }, /* 314 */ + { 0x20, 316, 0, 4, "secp224k1" }, /* 315 */ + { 0x21, 317, 0, 4, "secp224r1" }, /* 316 */ + { 0x22, 318, 0, 4, "secp384r1" }, /* 317 */ + { 0x23, 319, 0, 4, "secp521r1" }, /* 318 */ + { 0x24, 320, 0, 4, "sect409k1" }, /* 319 */ + { 0x25, 321, 0, 4, "sect409r1" }, /* 320 */ + { 0x26, 322, 0, 4, "sect571k1" }, /* 321 */ + { 0x27, 0, 0, 4, "sect571r1" }, /* 322 */ + {0x60, 369, 1, 0, "" }, /* 323 */ + { 0x86, 0, 1, 1, "" }, /* 324 */ + { 0x48, 0, 1, 2, "" }, /* 325 */ + { 0x01, 0, 1, 3, "organization" }, /* 326 */ + { 0x65, 345, 1, 4, "gov" }, /* 327 */ + { 0x03, 0, 1, 5, "csor" }, /* 328 */ + { 0x04, 0, 1, 6, "nistalgorithm" }, /* 329 */ + { 0x01, 340, 1, 7, "aes" }, /* 330 */ + { 0x02, 332, 0, 8, "id-aes128-CBC" }, /* 331 */ + { 0x06, 333, 0, 8, "id-aes128-GCM" }, /* 332 */ + { 0x07, 334, 0, 8, "id-aes128-CCM" }, /* 333 */ + { 0x16, 335, 0, 8, "id-aes192-CBC" }, /* 334 */ + { 0x1A, 336, 0, 8, "id-aes192-GCM" }, /* 335 */ + { 0x1B, 337, 0, 8, "id-aes192-CCM" }, /* 336 */ + { 0x2A, 338, 0, 8, "id-aes256-CBC" }, /* 337 */ + { 0x2E, 339, 0, 8, "id-aes256-GCM" }, /* 338 */ + { 0x2F, 0, 0, 8, "id-aes256-CCM" }, /* 339 */ + { 0x02, 0, 1, 7, "hashalgs" }, /* 340 */ + { 0x01, 342, 0, 8, "id-SHA-256" }, /* 341 */ + { 0x02, 343, 0, 8, "id-SHA-384" }, /* 342 */ + { 0x03, 344, 0, 8, "id-SHA-512" }, /* 343 */ + { 0x04, 0, 0, 8, "id-SHA-224" }, /* 344 */ + { 0x86, 0, 1, 4, "" }, /* 345 */ + { 0xf8, 0, 1, 5, "" }, /* 346 */ + { 0x42, 359, 1, 6, "netscape" }, /* 347 */ + { 0x01, 354, 1, 7, "" }, /* 348 */ + { 0x01, 350, 0, 8, "nsCertType" }, /* 349 */ + { 0x03, 351, 0, 8, "nsRevocationUrl" }, /* 350 */ + { 0x04, 352, 0, 8, "nsCaRevocationUrl" }, /* 351 */ + { 0x08, 353, 0, 8, "nsCaPolicyUrl" }, /* 352 */ + { 0x0d, 0, 0, 8, "nsComment" }, /* 353 */ + { 0x03, 357, 1, 7, "directory" }, /* 354 */ + { 0x01, 0, 1, 8, "" }, /* 355 */ + { 0x03, 0, 0, 9, "employeeNumber" }, /* 356 */ + { 0x04, 0, 1, 7, "policy" }, /* 357 */ + { 0x01, 0, 0, 8, "nsSGC" }, /* 358 */ + { 0x45, 0, 1, 6, "verisign" }, /* 359 */ + { 0x01, 0, 1, 7, "pki" }, /* 360 */ + { 0x09, 0, 1, 8, "attributes" }, /* 361 */ + { 0x02, 363, 0, 9, "messageType" }, /* 362 */ + { 0x03, 364, 0, 9, "pkiStatus" }, /* 363 */ + { 0x04, 365, 0, 9, "failInfo" }, /* 364 */ + { 0x05, 366, 0, 9, "senderNonce" }, /* 365 */ + { 0x06, 367, 0, 9, "recipientNonce" }, /* 366 */ + { 0x07, 368, 0, 9, "transID" }, /* 367 */ + { 0x08, 0, 0, 9, "extensionReq" }, /* 368 */ + {0x67, 0, 1, 0, "" }, /* 369 */ + { 0x81, 0, 1, 1, "" }, /* 370 */ + { 0x05, 0, 1, 2, "" }, /* 371 */ + { 0x02, 0, 1, 3, "tcg-attribute" }, /* 372 */ + { 0x01, 374, 0, 4, "tcg-at-tpmManufacturer" }, /* 373 */ + { 0x02, 375, 0, 4, "tcg-at-tpmModel" }, /* 374 */ + { 0x03, 376, 0, 4, "tcg-at-tpmVersion" }, /* 375 */ + { 0x0F, 0, 0, 4, "tcg-at-tpmIdLabel" } /* 376 */ }; diff --git a/src/libstrongswan/asn1/oid.h b/src/libstrongswan/asn1/oid.h index a01c434a9..5e30a3675 100644 --- a/src/libstrongswan/asn1/oid.h +++ b/src/libstrongswan/asn1/oid.h @@ -150,76 +150,77 @@ extern const oid_t oid_names[]; #define OID_ARCHIVE_CUTOFF 229 #define OID_SERVICE_LOCATOR 230 #define OID_CA_ISSUERS 231 -#define OID_DES_CBC 237 -#define OID_SHA1 238 -#define OID_SHA1_WITH_RSA_OIW 239 -#define OID_ECGDSA_PUBKEY 258 -#define OID_ECGDSA_SIG_WITH_RIPEMD160 261 -#define OID_ECGDSA_SIG_WITH_SHA1 262 -#define OID_ECGDSA_SIG_WITH_SHA224 263 -#define OID_ECGDSA_SIG_WITH_SHA256 264 -#define OID_ECGDSA_SIG_WITH_SHA384 265 -#define OID_ECGDSA_SIG_WITH_SHA512 266 -#define OID_SECT163K1 289 -#define OID_SECT163R1 290 -#define OID_SECT239K1 291 -#define OID_SECT113R1 292 -#define OID_SECT113R2 293 -#define OID_SECT112R1 294 -#define OID_SECT112R2 295 -#define OID_SECT160R1 296 -#define OID_SECT160K1 297 -#define OID_SECT256K1 298 -#define OID_SECT163R2 299 -#define OID_SECT283K1 300 -#define OID_SECT283R1 301 -#define OID_SECT131R1 302 -#define OID_SECT131R2 303 -#define OID_SECT193R1 304 -#define OID_SECT193R2 305 -#define OID_SECT233K1 306 -#define OID_SECT233R1 307 -#define OID_SECT128R1 308 -#define OID_SECT128R2 309 -#define OID_SECT160R2 310 -#define OID_SECT192K1 311 -#define OID_SECT224K1 312 -#define OID_SECT224R1 313 -#define OID_SECT384R1 314 -#define OID_SECT521R1 315 -#define OID_SECT409K1 316 -#define OID_SECT409R1 317 -#define OID_SECT571K1 318 -#define OID_SECT571R1 319 -#define OID_AES128_CBC 328 -#define OID_AES128_GCM 329 -#define OID_AES128_CCM 330 -#define OID_AES192_CBC 331 -#define OID_AES192_GCM 332 -#define OID_AES192_CCM 333 -#define OID_AES256_CBC 334 -#define OID_AES256_GCM 335 -#define OID_AES256_CCM 336 -#define OID_SHA256 338 -#define OID_SHA384 339 -#define OID_SHA512 340 -#define OID_SHA224 341 -#define OID_NS_REVOCATION_URL 347 -#define OID_NS_CA_REVOCATION_URL 348 -#define OID_NS_CA_POLICY_URL 349 -#define OID_NS_COMMENT 350 -#define OID_EMPLOYEE_NUMBER 353 -#define OID_PKI_MESSAGE_TYPE 359 -#define OID_PKI_STATUS 360 -#define OID_PKI_FAIL_INFO 361 -#define OID_PKI_SENDER_NONCE 362 -#define OID_PKI_RECIPIENT_NONCE 363 -#define OID_PKI_TRANS_ID 364 -#define OID_TPM_MANUFACTURER 370 -#define OID_TPM_MODEL 371 -#define OID_TPM_VERSION 372 -#define OID_TPM_ID_LABEL 373 +#define OID_IKE_INTERMEDIATE 236 +#define OID_DES_CBC 240 +#define OID_SHA1 241 +#define OID_SHA1_WITH_RSA_OIW 242 +#define OID_ECGDSA_PUBKEY 261 +#define OID_ECGDSA_SIG_WITH_RIPEMD160 264 +#define OID_ECGDSA_SIG_WITH_SHA1 265 +#define OID_ECGDSA_SIG_WITH_SHA224 266 +#define OID_ECGDSA_SIG_WITH_SHA256 267 +#define OID_ECGDSA_SIG_WITH_SHA384 268 +#define OID_ECGDSA_SIG_WITH_SHA512 269 +#define OID_SECT163K1 292 +#define OID_SECT163R1 293 +#define OID_SECT239K1 294 +#define OID_SECT113R1 295 +#define OID_SECT113R2 296 +#define OID_SECT112R1 297 +#define OID_SECT112R2 298 +#define OID_SECT160R1 299 +#define OID_SECT160K1 300 +#define OID_SECT256K1 301 +#define OID_SECT163R2 302 +#define OID_SECT283K1 303 +#define OID_SECT283R1 304 +#define OID_SECT131R1 305 +#define OID_SECT131R2 306 +#define OID_SECT193R1 307 +#define OID_SECT193R2 308 +#define OID_SECT233K1 309 +#define OID_SECT233R1 310 +#define OID_SECT128R1 311 +#define OID_SECT128R2 312 +#define OID_SECT160R2 313 +#define OID_SECT192K1 314 +#define OID_SECT224K1 315 +#define OID_SECT224R1 316 +#define OID_SECT384R1 317 +#define OID_SECT521R1 318 +#define OID_SECT409K1 319 +#define OID_SECT409R1 320 +#define OID_SECT571K1 321 +#define OID_SECT571R1 322 +#define OID_AES128_CBC 331 +#define OID_AES128_GCM 332 +#define OID_AES128_CCM 333 +#define OID_AES192_CBC 334 +#define OID_AES192_GCM 335 +#define OID_AES192_CCM 336 +#define OID_AES256_CBC 337 +#define OID_AES256_GCM 338 +#define OID_AES256_CCM 339 +#define OID_SHA256 341 +#define OID_SHA384 342 +#define OID_SHA512 343 +#define OID_SHA224 344 +#define OID_NS_REVOCATION_URL 350 +#define OID_NS_CA_REVOCATION_URL 351 +#define OID_NS_CA_POLICY_URL 352 +#define OID_NS_COMMENT 353 +#define OID_EMPLOYEE_NUMBER 356 +#define OID_PKI_MESSAGE_TYPE 362 +#define OID_PKI_STATUS 363 +#define OID_PKI_FAIL_INFO 364 +#define OID_PKI_SENDER_NONCE 365 +#define OID_PKI_RECIPIENT_NONCE 366 +#define OID_PKI_TRANS_ID 367 +#define OID_TPM_MANUFACTURER 373 +#define OID_TPM_MODEL 374 +#define OID_TPM_VERSION 375 +#define OID_TPM_ID_LABEL 376 -#define OID_MAX 374 +#define OID_MAX 377 #endif /* OID_H_ */ diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index c3ff1a9e7..51a29eb33 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -232,6 +232,9 @@ 0x02 "caIssuers" OID_CA_ISSUERS 0x03 "timeStamping" 0x05 "caRepository" + 0x08 "ipsec" + 0x02 "certificate" + 0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE 0x0E "oiw" 0x03 "secsig" 0x02 "algorithms" diff --git a/src/libstrongswan/bio/bio_reader.c b/src/libstrongswan/bio/bio_reader.c index fce0d1aef..3a62bb541 100644 --- a/src/libstrongswan/bio/bio_reader.c +++ b/src/libstrongswan/bio/bio_reader.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -47,8 +50,38 @@ METHOD(bio_reader_t, peek, chunk_t, return this->buf; } -METHOD(bio_reader_t, read_uint8, bool, - private_bio_reader_t *this, u_int8_t *res) +/** + * A version of chunk_skip() that supports skipping from the end (i.e. simply + * reducing the size) + */ +static inline chunk_t chunk_skip_end(chunk_t chunk, size_t bytes, bool from_end) +{ + if (chunk.len > bytes) + { + if (!from_end) + { + chunk.ptr += bytes; + } + chunk.len -= bytes; + return chunk; + } + return chunk_empty; +} + +/** + * Returns a pointer to the data to read, optionally from the end + */ +static inline u_char *get_ptr_end(private_bio_reader_t *this, u_int32_t len, + bool from_end) +{ + return from_end ? this->buf.ptr + (this->buf.len - len) : this->buf.ptr; +} + +/** + * Read an u_int8_t from the buffer, optionally from the end of the buffer + */ +static bool read_uint8_internal(private_bio_reader_t *this, u_int8_t *res, + bool from_end) { if (this->buf.len < 1) { @@ -56,13 +89,16 @@ METHOD(bio_reader_t, read_uint8, bool, this->buf.len); return FALSE; } - *res = this->buf.ptr[0]; - this->buf = chunk_skip(this->buf, 1); + *res = *get_ptr_end(this, 1, from_end); + this->buf = chunk_skip_end(this->buf, 1, from_end); return TRUE; } -METHOD(bio_reader_t, read_uint16, bool, - private_bio_reader_t *this, u_int16_t *res) +/** + * Read an u_int16_t from the buffer, optionally from the end + */ +static bool read_uint16_internal(private_bio_reader_t *this, u_int16_t *res, + bool from_end) { if (this->buf.len < 2) { @@ -70,13 +106,16 @@ METHOD(bio_reader_t, read_uint16, bool, this->buf.len); return FALSE; } - *res = untoh16(this->buf.ptr); - this->buf = chunk_skip(this->buf, 2); + *res = untoh16(get_ptr_end(this, 2, from_end)); + this->buf = chunk_skip_end(this->buf, 2, from_end); return TRUE; } -METHOD(bio_reader_t, read_uint24, bool, - private_bio_reader_t *this, u_int32_t *res) +/** + * Read an u_int32_t (only 24-bit) from the buffer, optionally from the end + */ +static bool read_uint24_internal(private_bio_reader_t *this, u_int32_t *res, + bool from_end) { if (this->buf.len < 3) { @@ -84,13 +123,16 @@ METHOD(bio_reader_t, read_uint24, bool, this->buf.len); return FALSE; } - *res = untoh32(this->buf.ptr) >> 8; - this->buf = chunk_skip(this->buf, 3); + *res = untoh32(get_ptr_end(this, 3, from_end)) >> 8; + this->buf = chunk_skip_end(this->buf, 3, from_end); return TRUE; } -METHOD(bio_reader_t, read_uint32, bool, - private_bio_reader_t *this, u_int32_t *res) +/** + * Read an u_int32_t from the buffer, optionally from the end + */ +static bool read_uint32_internal(private_bio_reader_t *this, u_int32_t *res, + bool from_end) { if (this->buf.len < 4) { @@ -98,13 +140,16 @@ METHOD(bio_reader_t, read_uint32, bool, this->buf.len); return FALSE; } - *res = untoh32(this->buf.ptr); - this->buf = chunk_skip(this->buf, 4); + *res = untoh32(get_ptr_end(this, 4, from_end)); + this->buf = chunk_skip_end(this->buf, 4, from_end); return TRUE; } -METHOD(bio_reader_t, read_uint64, bool, - private_bio_reader_t *this, u_int64_t *res) +/** + * Read an u_int64_t from the buffer, optionally from the end + */ +static bool read_uint64_internal(private_bio_reader_t *this, u_int64_t *res, + bool from_end) { if (this->buf.len < 8) { @@ -112,13 +157,16 @@ METHOD(bio_reader_t, read_uint64, bool, this->buf.len); return FALSE; } - *res = untoh64(this->buf.ptr); - this->buf = chunk_skip(this->buf, 8); + *res = untoh64(get_ptr_end(this, 8, from_end)); + this->buf = chunk_skip_end(this->buf, 8, from_end); return TRUE; } -METHOD(bio_reader_t, read_data, bool, - private_bio_reader_t *this, u_int32_t len, chunk_t *res) +/** + * Read a chunk of data from the buffer, optionally from the end + */ +static bool read_data_internal(private_bio_reader_t *this, u_int32_t len, + chunk_t *res, bool from_end) { if (this->buf.len < len) { @@ -126,11 +174,83 @@ METHOD(bio_reader_t, read_data, bool, this->buf.len, len); return FALSE; } - *res = chunk_create(this->buf.ptr, len); - this->buf = chunk_skip(this->buf, len); + *res = chunk_create(get_ptr_end(this, len, from_end), len); + this->buf = chunk_skip_end(this->buf, len, from_end); return TRUE; } +METHOD(bio_reader_t, read_uint8, bool, + private_bio_reader_t *this, u_int8_t *res) +{ + return read_uint8_internal(this, res, FALSE); +} + +METHOD(bio_reader_t, read_uint16, bool, + private_bio_reader_t *this, u_int16_t *res) +{ + return read_uint16_internal(this, res, FALSE); +} + +METHOD(bio_reader_t, read_uint24, bool, + private_bio_reader_t *this, u_int32_t *res) +{ + return read_uint24_internal(this, res, FALSE); +} + +METHOD(bio_reader_t, read_uint32, bool, + private_bio_reader_t *this, u_int32_t *res) +{ + return read_uint32_internal(this, res, FALSE); +} + +METHOD(bio_reader_t, read_uint64, bool, + private_bio_reader_t *this, u_int64_t *res) +{ + return read_uint64_internal(this, res, FALSE); +} + +METHOD(bio_reader_t, read_data, bool, + private_bio_reader_t *this, u_int32_t len, chunk_t *res) +{ + return read_data_internal(this, len, res, FALSE); +} + +METHOD(bio_reader_t, read_uint8_end, bool, + private_bio_reader_t *this, u_int8_t *res) +{ + return read_uint8_internal(this, res, TRUE); +} + +METHOD(bio_reader_t, read_uint16_end, bool, + private_bio_reader_t *this, u_int16_t *res) +{ + return read_uint16_internal(this, res, TRUE); +} + +METHOD(bio_reader_t, read_uint24_end, bool, + private_bio_reader_t *this, u_int32_t *res) +{ + return read_uint24_internal(this, res, TRUE); +} + +METHOD(bio_reader_t, read_uint32_end, bool, + private_bio_reader_t *this, u_int32_t *res) +{ + return read_uint32_internal(this, res, TRUE); +} + +METHOD(bio_reader_t, read_uint64_end, bool, + private_bio_reader_t *this, u_int64_t *res) +{ + return read_uint64_internal(this, res, TRUE); +} + +METHOD(bio_reader_t, read_data_end, bool, + private_bio_reader_t *this, u_int32_t len, chunk_t *res) +{ + return read_data_internal(this, len, res, TRUE); +} + METHOD(bio_reader_t, read_data8, bool, private_bio_reader_t *this, chunk_t *res) { @@ -202,6 +322,12 @@ bio_reader_t *bio_reader_create(chunk_t data) .read_uint32 = _read_uint32, .read_uint64 = _read_uint64, .read_data = _read_data, + .read_uint8_end = _read_uint8_end, + .read_uint16_end = _read_uint16_end, + .read_uint24_end = _read_uint24_end, + .read_uint32_end = _read_uint32_end, + .read_uint64_end = _read_uint64_end, + .read_data_end = _read_data_end, .read_data8 = _read_data8, .read_data16 = _read_data16, .read_data24 = _read_data24, diff --git a/src/libstrongswan/bio/bio_reader.h b/src/libstrongswan/bio/bio_reader.h index 85434a784..3162f3eda 100644 --- a/src/libstrongswan/bio/bio_reader.h +++ b/src/libstrongswan/bio/bio_reader.h @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -27,6 +30,8 @@ typedef struct bio_reader_t bio_reader_t; /** * Buffered input parser. + * + * @note Integers are returned in host byte order. */ struct bio_reader_t { @@ -93,6 +98,55 @@ struct bio_reader_t { */ bool (*read_data)(bio_reader_t *this, u_int32_t len, chunk_t *res); + /** + * Read a 8-bit integer from the end of the buffer, reduce remaining. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint8_end)(bio_reader_t *this, u_int8_t *res); + + /** + * Read a 16-bit integer from the end of the buffer, reduce remaining. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint16_end)(bio_reader_t *this, u_int16_t *res); + + /** + * Read a 24-bit integer from the end of the buffer, reduce remaining. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint24_end)(bio_reader_t *this, u_int32_t *res); + + /** + * Read a 32-bit integer from the end of the buffer, reduce remaining. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint32_end)(bio_reader_t *this, u_int32_t *res); + + /** + * Read a 64-bit integer from the end of the buffer, reduce remaining. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint64_end)(bio_reader_t *this, u_int64_t *res); + + /** + * Read a chunk of len bytes from the end of the buffer, reduce remaining. + * + * @param len number of bytes to read + * @param res ponter to result, not cloned + * @return TRUE if data read successfully + */ + bool (*read_data_end)(bio_reader_t *this, u_int32_t len, chunk_t *res); + /** * Read a chunk of bytes with a 8-bit length header, advance. * diff --git a/src/libstrongswan/bio/bio_writer.c b/src/libstrongswan/bio/bio_writer.c index bf373d6ac..8576843ee 100644 --- a/src/libstrongswan/bio/bio_writer.c +++ b/src/libstrongswan/bio/bio_writer.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -199,12 +202,35 @@ METHOD(bio_writer_t, wrap32, void, this->used += 4; } +METHOD(bio_writer_t, skip, chunk_t, + private_bio_writer_t *this, size_t len) +{ + chunk_t skipped; + + while (this->used + len > this->buf.len) + { + increase(this); + } + skipped = chunk_create(this->buf.ptr + this->used, len); + this->used += len; + return skipped; +} + METHOD(bio_writer_t, get_buf, chunk_t, private_bio_writer_t *this) { return chunk_create(this->buf.ptr, this->used); } +METHOD(bio_writer_t, extract_buf, chunk_t, + private_bio_writer_t *this) +{ + chunk_t buf = get_buf(this); + this->buf = chunk_empty; + this->used = 0; + return buf; +} + METHOD(bio_writer_t, destroy, void, private_bio_writer_t *this) { @@ -235,7 +261,9 @@ bio_writer_t *bio_writer_create(u_int32_t bufsize) .wrap16 = _wrap16, .wrap24 = _wrap24, .wrap32 = _wrap32, + .skip = _skip, .get_buf = _get_buf, + .extract_buf = _extract_buf, .destroy = _destroy, }, .increase = bufsize ? max(bufsize, 4) : 32, diff --git a/src/libstrongswan/bio/bio_writer.h b/src/libstrongswan/bio/bio_writer.h index 0b50f7882..57a5c3d38 100644 --- a/src/libstrongswan/bio/bio_writer.h +++ b/src/libstrongswan/bio/bio_writer.h @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -27,6 +30,8 @@ typedef struct bio_writer_t bio_writer_t; /** * Buffered output generator. + * + * @note Integers are converted to network byte order before writing. */ struct bio_writer_t { @@ -120,6 +125,15 @@ struct bio_writer_t { */ void (*wrap32)(bio_writer_t *this); + /** + * Skips len bytes in the buffer before the next data is written, returns + * a chunk covering the skipped bytes. + * + * @param len number of bytes to skip + * @return chunk pointing to skipped bytes in the internal buffer + */ + chunk_t (*skip)(bio_writer_t *this, size_t len); + /** * Get the encoded data buffer. * @@ -127,6 +141,14 @@ struct bio_writer_t { */ chunk_t (*get_buf)(bio_writer_t *this); + /** + * Return the encoded data buffer and detach it from the writer (resets + * the internal buffer). + * + * @return chunk to internal buffer (has to be freed) + */ + chunk_t (*extract_buf)(bio_writer_t *this); + /** * Destroy a bio_writer_t. */ @@ -136,6 +158,9 @@ struct bio_writer_t { /** * Create a bio_writer instance. * + * The size of the internal buffer is increased automatically by bufsize (or a + * default if not given) if the initial size does not suffice. + * * @param bufsize initially allocated buffer size */ bio_writer_t *bio_writer_create(u_int32_t bufsize); diff --git a/src/libstrongswan/chunk.c b/src/libstrongswan/chunk.c index 9397c4e44..d7f1c31d9 100644 --- a/src/libstrongswan/chunk.c +++ b/src/libstrongswan/chunk.c @@ -658,7 +658,7 @@ u_int32_t chunk_hash(chunk_t chunk) /** * Described in header. */ -int chunk_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { chunk_t *chunk = *((chunk_t**)(args[0])); @@ -670,7 +670,7 @@ int chunk_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, { u_int chunk_len = chunk->len; const void *new_args[] = {&chunk->ptr, &chunk_len}; - return mem_printf_hook(dst, len, spec, new_args); + return mem_printf_hook(data, spec, new_args); } while (copy.len > 0) @@ -681,9 +681,9 @@ int chunk_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, } else { - written += print_in_hook(dst, len, ":"); + written += print_in_hook(data, ":"); } - written += print_in_hook(dst, len, "%02x", *copy.ptr++); + written += print_in_hook(data, "%02x", *copy.ptr++); copy.len--; } return written; diff --git a/src/libstrongswan/chunk.h b/src/libstrongswan/chunk.h index 3de02eee7..91b23da3b 100644 --- a/src/libstrongswan/chunk.h +++ b/src/libstrongswan/chunk.h @@ -264,6 +264,15 @@ static inline bool chunk_equals(chunk_t a, chunk_t b) a.len == b.len && memeq(a.ptr, b.ptr, a.len); } +/** + * Compare two chunks (given as pointers) for equality (useful as callback), + * NULL chunks are never equal. + */ +static inline bool chunk_equals_ptr(chunk_t *a, chunk_t *b) +{ + return a != NULL && b != NULL && chunk_equals(*a, *b); +} + /** * Increment a chunk, as it would reprensent a network order integer. * @@ -303,7 +312,7 @@ u_int32_t chunk_hash_inc(chunk_t chunk, u_int32_t hash); * chunk_t *chunk * Use #-modifier to print a compact version */ -int chunk_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** CHUNK_H_ @}*/ diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 12f75b240..6ee4f9b6e 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -23,20 +23,24 @@ #include #include -ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_EAP, +ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_XAUTH, "any", "public key", "pre-shared key", "EAP", + "XAuth", ); ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT, "RULE_IDENTITY", + "RULE_IDENTITY_LOOSE", "RULE_AUTH_CLASS", "RULE_AAA_IDENTITY", "RULE_EAP_IDENTITY", "RULE_EAP_TYPE", "RULE_EAP_VENDOR", + "RULE_XAUTH_BACKEND", + "RULE_XAUTH_IDENTITY", "RULE_CA_CERT", "RULE_IM_CERT", "RULE_SUBJECT_CERT", @@ -45,6 +49,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT, "RULE_GROUP", "RULE_RSA_STRENGTH", "RULE_ECDSA_STRENGTH", + "RULE_SIGNATURE_SCHEME", "RULE_CERT_POLICY", "HELPER_IM_CERT", "HELPER_SUBJECT_CERT", @@ -66,8 +71,11 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_IDENTITY: + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_SUBJECT_CERT: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_SUBJECT_HASH_URL: @@ -79,6 +87,7 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: case AUTH_RULE_CERT_POLICY: + case AUTH_RULE_SIGNATURE_SCHEME: case AUTH_HELPER_IM_CERT: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_REVOCATION_CERT: @@ -190,6 +199,7 @@ static entry_t *entry_create(auth_rule_t type, va_list args) this->type = type; switch (type) { + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_AUTH_CLASS: case AUTH_RULE_EAP_TYPE: case AUTH_RULE_EAP_VENDOR: @@ -197,12 +207,15 @@ static entry_t *entry_create(auth_rule_t type, va_list args) case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: /* integer type */ this->value = (void*)(uintptr_t)va_arg(args, u_int); break; case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -234,6 +247,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2) } switch (e1->type) { + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_AUTH_CLASS: case AUTH_RULE_EAP_TYPE: case AUTH_RULE_EAP_VENDOR: @@ -241,6 +255,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2) case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: { return e1->value == e2->value; } @@ -261,6 +276,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2) case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: { identification_t *id1, *id2; @@ -271,6 +287,7 @@ static bool entry_equals(entry_t *e1, entry_t *e2) return id1->equals(id1, id2); } case AUTH_RULE_CERT_POLICY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: { @@ -293,6 +310,7 @@ static void destroy_entry_value(entry_t *entry) case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)entry->value; id->destroy(id); @@ -310,12 +328,14 @@ static void destroy_entry_value(entry_t *entry) break; } case AUTH_RULE_CERT_POLICY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: { free(entry->value); break; } + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_AUTH_CLASS: case AUTH_RULE_EAP_TYPE: case AUTH_RULE_EAP_VENDOR: @@ -323,6 +343,7 @@ static void destroy_entry_value(entry_t *entry) case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: case AUTH_RULE_MAX: break; } @@ -345,6 +366,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, entry->type = type; switch (type) { + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_AUTH_CLASS: case AUTH_RULE_EAP_TYPE: case AUTH_RULE_EAP_VENDOR: @@ -352,12 +374,15 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: /* integer type */ entry->value = (void*)(uintptr_t)va_arg(args, u_int); break; case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -423,12 +448,18 @@ METHOD(auth_cfg_t, get, void*, case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: return (void*)0; + case AUTH_RULE_SIGNATURE_SCHEME: + return HASH_UNKNOWN; case AUTH_RULE_CRL_VALIDATION: case AUTH_RULE_OCSP_VALIDATION: return (void*)VALIDATION_FAILED; + case AUTH_RULE_IDENTITY_LOOSE: + return (void*)FALSE; case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -472,7 +503,10 @@ METHOD(auth_cfg_t, complies, bool, private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error) { enumerator_t *e1, *e2; - bool success = TRUE, has_group = FALSE, group_match = FALSE; + bool success = TRUE, group_match = FALSE; + identification_t *require_group = NULL; + signature_scheme_t scheme = SIGN_UNKNOWN; + u_int strength = 0; auth_rule_t t1, t2; void *value; @@ -571,6 +605,7 @@ METHOD(auth_cfg_t, complies, bool, case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id1, *id2; @@ -578,6 +613,17 @@ METHOD(auth_cfg_t, complies, bool, id2 = get(this, t1); if (!id2 || !id2->matches(id2, id1)) { + if (t1 == AUTH_RULE_IDENTITY && + constraints->get(constraints, AUTH_RULE_IDENTITY_LOOSE)) + { /* also verify identity against subjectAltNames */ + certificate_t *cert; + + cert = get(this, AUTH_HELPER_SUBJECT_CERT); + if (cert && cert->has_subject(cert, id1)) + { + break; + } + } success = FALSE; if (log_error) { @@ -633,15 +679,15 @@ METHOD(auth_cfg_t, complies, bool, } case AUTH_RULE_GROUP: { - identification_t *id1, *id2; + identification_t *group; /* for groups, a match of a single group is sufficient */ - has_group = TRUE; - id1 = (identification_t*)value; + require_group = (identification_t*)value; e2 = create_enumerator(this); - while (e2->enumerate(e2, &t2, &id2)) + while (e2->enumerate(e2, &t2, &group)) { - if (t2 == AUTH_RULE_GROUP && id2->matches(id2, id1)) + if (t2 == AUTH_RULE_GROUP && + group->matches(group, require_group)) { group_match = TRUE; } @@ -652,44 +698,12 @@ METHOD(auth_cfg_t, complies, bool, case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: { - uintptr_t strength; - - e2 = create_enumerator(this); - while (e2->enumerate(e2, &t2, &strength)) - { - if (t2 == t1) - { - if ((uintptr_t)value > strength) - { - success = FALSE; - if (log_error) - { - DBG1(DBG_CFG, "constraint requires %d bit " - "public keys, but %d bit key used", - (uintptr_t)value, strength); - } - } - } - else if (t2 == AUTH_RULE_RSA_STRENGTH) - { - success = FALSE; - if (log_error) - { - DBG1(DBG_CFG, "constraint requires %d bit ECDSA, " - "but RSA used", (uintptr_t)value); - } - } - else if (t2 == AUTH_RULE_ECDSA_STRENGTH) - { - success = FALSE; - if (log_error) - { - DBG1(DBG_CFG, "constraint requires %d bit RSA, " - "but ECDSA used", (uintptr_t)value); - } - } - } - e2->destroy(e2); + strength = (uintptr_t)value; + break; + } + case AUTH_RULE_SIGNATURE_SCHEME: + { + scheme = (uintptr_t)value; break; } case AUTH_RULE_CERT_POLICY: @@ -714,6 +728,10 @@ METHOD(auth_cfg_t, complies, bool, } break; } + case AUTH_RULE_IDENTITY_LOOSE: + /* just an indication when verifying AUTH_RULE_IDENTITY */ + case AUTH_RULE_XAUTH_BACKEND: + /* not enforced, just a hint for local authentication */ case AUTH_HELPER_IM_CERT: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_IM_HASH_URL: @@ -730,11 +748,83 @@ METHOD(auth_cfg_t, complies, bool, } e1->destroy(e1); - if (has_group && !group_match) + /* Check if we have a matching constraint (or none at all) for used + * signature schemes. */ + if (success && scheme != SIGN_UNKNOWN) + { + e2 = create_enumerator(this); + while (e2->enumerate(e2, &t2, &scheme)) + { + if (t2 == AUTH_RULE_SIGNATURE_SCHEME) + { + success = FALSE; + e1 = constraints->create_enumerator(constraints); + while (e1->enumerate(e1, &t1, &value)) + { + if (t1 == AUTH_RULE_SIGNATURE_SCHEME && + (uintptr_t)value == scheme) + { + success = TRUE; + break; + } + } + e1->destroy(e1); + if (!success) + { + if (log_error) + { + DBG1(DBG_CFG, "signature scheme %N not acceptable", + signature_scheme_names, (int)scheme); + } + break; + } + } + } + e2->destroy(e2); + } + + /* Check if we have a matching constraint (or none at all) for used + * public key strength */ + if (success && strength) + { + e2 = create_enumerator(this); + while (e2->enumerate(e2, &t2, &strength)) + { + if (t2 == AUTH_RULE_RSA_STRENGTH || + t2 == AUTH_RULE_ECDSA_STRENGTH) + { + success = FALSE; + e1 = constraints->create_enumerator(constraints); + while (e1->enumerate(e1, &t1, &value)) + { + if (t1 == t2 && (uintptr_t)value <= strength) + { + success = TRUE; + break; + } + } + e1->destroy(e1); + if (!success) + { + if (log_error) + { + DBG1(DBG_CFG, "%s-%d signatures not acceptable", + t2 == AUTH_RULE_RSA_STRENGTH ? "RSA" : "ECDSA", + strength); + } + break; + } + } + } + e2->destroy(e2); + } + + if (require_group && !group_match) { if (log_error) { - DBG1(DBG_CFG, "constraint check failed: group membership required"); + DBG1(DBG_CFG, "constraint check failed: group membership to " + "'%Y' required", require_group); } return FALSE; } @@ -774,6 +864,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy add(this, type, cert->get_ref(cert)); break; } + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_CRL_VALIDATION: case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_AUTH_CLASS: @@ -781,6 +872,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy case AUTH_RULE_EAP_VENDOR: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: { add(this, type, (uintptr_t)value); break; @@ -789,12 +881,14 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)value; add(this, type, id->clone(id)); break; } + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_CERT_POLICY: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: @@ -821,9 +915,9 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy } /** - * Implementation of auth_cfg_t.equals. + * Compare two auth_cfg_t objects for equality. */ -static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) +static bool auth_cfg_equals(private_auth_cfg_t *this, private_auth_cfg_t *other) { enumerator_t *e1, *e2; entry_t *i1, *i2; @@ -860,6 +954,20 @@ static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) return equal; } +/** + * Implementation of auth_cfg_t.equals. + */ +static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) +{ + if (auth_cfg_equals(this, other)) + { + /* as 'other' might contain entries that 'this' doesn't we also check + * the other way around */ + return auth_cfg_equals(other, this); + } + return FALSE; +} + METHOD(auth_cfg_t, purge, void, private_auth_cfg_t *this, bool keep_ca) { @@ -904,6 +1012,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)entry->value; clone->add(clone, entry->type, id->clone(id)); @@ -920,6 +1029,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, clone->add(clone, entry->type, cert->get_ref(cert)); break; } + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_CERT_POLICY: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: @@ -927,6 +1037,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, clone->add(clone, entry->type, strdup(entry->value)); break; } + case AUTH_RULE_IDENTITY_LOOSE: case AUTH_RULE_AUTH_CLASS: case AUTH_RULE_EAP_TYPE: case AUTH_RULE_EAP_VENDOR: @@ -934,6 +1045,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: + case AUTH_RULE_SIGNATURE_SCHEME: clone->add(clone, entry->type, (uintptr_t)entry->value); break; case AUTH_RULE_MAX: diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 4d12a9c14..79484a04c 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -42,6 +42,8 @@ enum auth_class_t { AUTH_CLASS_PSK = 2, /** authentication using EAP */ AUTH_CLASS_EAP = 3, + /** authentication using IKEv1 XAUTH */ + AUTH_CLASS_XAUTH = 4, }; /** @@ -65,6 +67,9 @@ extern enum_name_t *auth_class_names; enum auth_rule_t { /** identity to use for IKEv2 authentication exchange, identification_t* */ AUTH_RULE_IDENTITY, + /** if TRUE don't send IDr as initiator, but verify the identity after + * receiving IDr (but also verify it against subjectAltNames), bool */ + AUTH_RULE_IDENTITY_LOOSE, /** authentication class, auth_class_t */ AUTH_RULE_AUTH_CLASS, /** AAA-backend identity for EAP methods supporting it, identification_t* */ @@ -75,6 +80,10 @@ enum auth_rule_t { AUTH_RULE_EAP_TYPE, /** EAP vendor for vendor specific type, u_int32_t */ AUTH_RULE_EAP_VENDOR, + /** XAUTH backend name to use, char* */ + AUTH_RULE_XAUTH_BACKEND, + /** XAuth identity to use or require, identification_t* */ + AUTH_RULE_XAUTH_IDENTITY, /** certificate authority, certificate_t* */ AUTH_RULE_CA_CERT, /** intermediate certificate in trustchain, certificate_t* */ @@ -93,6 +102,8 @@ enum auth_rule_t { AUTH_RULE_RSA_STRENGTH, /** required ECDSA public key strength, u_int in bits */ AUTH_RULE_ECDSA_STRENGTH, + /** required signature scheme, signature_scheme_t */ + AUTH_RULE_SIGNATURE_SCHEME, /** certificatePolicy constraint, numerical OID as char* */ AUTH_RULE_CERT_POLICY, @@ -172,7 +183,7 @@ struct auth_cfg_t { * For rules we expect only once the latest value is returned. * * @param rule rule type - * @return bool if item has been found + * @return rule or NULL (or an appropriate default) if not found */ void* (*get)(auth_cfg_t *this, auth_rule_t rule); diff --git a/src/libstrongswan/credentials/certificates/certificate.h b/src/libstrongswan/credentials/certificates/certificate.h index 2f471da5b..b7a88ffbd 100644 --- a/src/libstrongswan/credentials/certificates/certificate.h +++ b/src/libstrongswan/credentials/certificates/certificate.h @@ -143,9 +143,11 @@ struct certificate_t { * Check if this certificate is issued and signed by a specific issuer. * * @param issuer issuer's certificate + * @param scheme receives signature scheme used during verification * @return TRUE if certificate issued by issuer and trusted */ - bool (*issued_by)(certificate_t *this, certificate_t *issuer); + bool (*issued_by)(certificate_t *this, certificate_t *issuer, + signature_scheme_t *scheme); /** * Get the public key associated to this certificate. diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index 5125aca26..00171a718 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -56,6 +56,8 @@ enum x509_flag_t { X509_IP_ADDR_BLOCKS = (1<<6), /** cert has CRL sign key usage */ X509_CRL_SIGN = (1<<7), + /** cert has iKEIntermediate key usage */ + X509_IKE_INTERMEDIATE = (1<<8), }; /** diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index b3461b810..a96abdc69 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -52,6 +52,11 @@ struct private_credential_manager_t { */ thread_value_t *local_sets; + /** + * Exclusive local sets, linked_list_t with credential_set_t + */ + thread_value_t *exclusive_local_sets; + /** * trust relationship and certificate cache */ @@ -117,12 +122,23 @@ typedef struct { enumerator_t *global; /** enumerator over local sets */ enumerator_t *local; + /** enumerator over exclusive local sets */ + enumerator_t *exclusive; } sets_enumerator_t; METHOD(enumerator_t, sets_enumerate, bool, sets_enumerator_t *this, credential_set_t **set) { + if (this->exclusive) + { + if (this->exclusive->enumerate(this->exclusive, set)) + { /* only enumerate last added */ + this->exclusive->destroy(this->exclusive); + this->exclusive = NULL; + return TRUE; + } + } if (this->global) { if (this->global->enumerate(this->global, set)) @@ -145,6 +161,7 @@ METHOD(enumerator_t, sets_destroy, void, { DESTROY_IF(this->global); DESTROY_IF(this->local); + DESTROY_IF(this->exclusive); free(this); } @@ -154,19 +171,28 @@ METHOD(enumerator_t, sets_destroy, void, static enumerator_t *create_sets_enumerator(private_credential_manager_t *this) { sets_enumerator_t *enumerator; - linked_list_t *local; + linked_list_t *list; INIT(enumerator, .public = { .enumerate = (void*)_sets_enumerate, .destroy = _sets_destroy, }, - .global = this->sets->create_enumerator(this->sets), ); - local = this->local_sets->get(this->local_sets); - if (local) + + list = this->exclusive_local_sets->get(this->exclusive_local_sets); + if (list && list->get_count(list)) + { + enumerator->exclusive = list->create_enumerator(list); + } + else { - enumerator->local = local->create_enumerator(local); + enumerator->global = this->sets->create_enumerator(this->sets); + list = this->local_sets->get(this->local_sets); + if (list) + { + enumerator->local = list->create_enumerator(list); + } } return &enumerator->public; } @@ -373,26 +399,66 @@ METHOD(credential_manager_t, get_shared, shared_key_t*, } METHOD(credential_manager_t, add_local_set, void, - private_credential_manager_t *this, credential_set_t *set) + private_credential_manager_t *this, credential_set_t *set, bool exclusive) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); + if (exclusive) + { + tv = this->exclusive_local_sets; + } + else + { + tv = this->local_sets; + } + sets = tv->get(tv); if (!sets) - { /* first invocation */ + { sets = linked_list_create(); - this->local_sets->set(this->local_sets, sets); + tv->set(tv, sets); + } + if (exclusive) + { + sets->insert_first(sets, set); + } + else + { + sets->insert_last(sets, set); } - sets->insert_last(sets, set); } METHOD(credential_manager_t, remove_local_set, void, private_credential_manager_t *this, credential_set_t *set) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); - sets->remove(sets, set, NULL); + tv = this->local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) + { + tv->set(tv, NULL); + sets->destroy(sets); + } + tv = this->exclusive_local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) + { + tv->set(tv, NULL); + sets->destroy(sets); + } +} + +METHOD(credential_manager_t, issued_by, bool, + private_credential_manager_t *this, certificate_t *subject, + certificate_t *issuer, signature_scheme_t *scheme) +{ + if (this->cache) + { + return this->cache->issued_by(this->cache, subject, issuer, scheme); + } + return subject->issued_by(subject, issuer, scheme); } METHOD(credential_manager_t, cache_cert, void, @@ -514,7 +580,8 @@ static certificate_t *get_pretrusted_cert(private_credential_manager_t *this, * Get the issuing certificate of a subject certificate */ static certificate_t *get_issuer_cert(private_credential_manager_t *this, - certificate_t *subject, bool trusted) + certificate_t *subject, bool trusted, + signature_scheme_t *scheme) { enumerator_t *enumerator; certificate_t *issuer = NULL, *candidate; @@ -523,7 +590,7 @@ static certificate_t *get_issuer_cert(private_credential_manager_t *this, subject->get_issuer(subject), trusted); while (enumerator->enumerate(enumerator, &candidate)) { - if (this->cache->issued_by(this->cache, subject, candidate)) + if (issued_by(this, subject, candidate, scheme)) { issuer = candidate->get_ref(candidate); break; @@ -573,6 +640,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, { certificate_t *current, *issuer; auth_cfg_t *auth; + signature_scheme_t scheme; int pathlen; auth = auth_cfg_create(); @@ -582,11 +650,11 @@ static bool verify_trust_chain(private_credential_manager_t *this, for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++) { - issuer = get_issuer_cert(this, current, TRUE); + issuer = get_issuer_cert(this, current, TRUE, &scheme); if (issuer) { /* accept only self-signed CAs as trust anchor */ - if (this->cache->issued_by(this->cache, issuer, issuer)) + if (issued_by(this, issuer, issuer, NULL)) { auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"", @@ -599,10 +667,11 @@ static bool verify_trust_chain(private_credential_manager_t *this, DBG1(DBG_CFG, " using trusted intermediate ca certificate " "\"%Y\"", issuer->get_subject(issuer)); } + auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, scheme); } else { - issuer = get_issuer_cert(this, current, FALSE); + issuer = get_issuer_cert(this, current, FALSE, &scheme); if (issuer) { if (current->equals(current, issuer)) @@ -615,6 +684,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, auth->add(auth, AUTH_RULE_IM_CERT, issuer->get_ref(issuer)); DBG1(DBG_CFG, " using untrusted intermediate certificate " "\"%Y\"", issuer->get_subject(issuer)); + auth->add(auth, AUTH_RULE_SIGNATURE_SCHEME, scheme); } else { @@ -708,8 +778,7 @@ METHOD(enumerator_t, trusted_enumerate, bool, /* if we find a trusted self signed certificate, we just accept it. * However, in order to fulfill authorization rules, we try to build * the trust chain if it is not self signed */ - if (this->this->cache->issued_by(this->this->cache, - this->pretrusted, this->pretrusted) || + if (issued_by(this->this, this->pretrusted, this->pretrusted, NULL) || verify_trust_chain(this->this, this->pretrusted, this->auth, TRUE, this->online)) { @@ -859,7 +928,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, if (auth) { enumerator->wrapper = auth_cfg_wrapper_create(auth); - add_local_set(this, &enumerator->wrapper->set); + add_local_set(this, &enumerator->wrapper->set, FALSE); } this->lock->read_lock(this->lock); return &enumerator->public; @@ -916,8 +985,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this, } else { - if (!has_anchor && - this->cache->issued_by(this->cache, current, current)) + if (!has_anchor && issued_by(this, current, current, NULL)) { /* If no trust anchor specified, accept any CA */ trustchain->add(trustchain, AUTH_RULE_CA_CERT, current); return trustchain; @@ -928,7 +996,7 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this, { break; } - issuer = get_issuer_cert(this, current, FALSE); + issuer = get_issuer_cert(this, current, FALSE, NULL); if (!issuer) { if (!has_anchor) @@ -992,42 +1060,45 @@ METHOD(credential_manager_t, get_private, private_key_t*, } } - /* if a specific certificate is preferred, check for a matching key */ - cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); - if (cert) + if (auth) { - private = get_private_by_cert(this, cert, type); - if (private) + /* if a specific certificate is preferred, check for a matching key */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + } + return private; } - return private; } - } - /* try to build a trust chain for each certificate found */ - enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); - while (enumerator->enumerate(enumerator, &cert)) - { - private = get_private_by_cert(this, cert, type); - if (private) + /* try to build a trust chain for each certificate found */ + enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); + while (enumerator->enumerate(enumerator, &cert)) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); - break; + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + break; + } + private->destroy(private); + private = NULL; } - private->destroy(private); - private = NULL; } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); /* if no valid trustchain was found, fall back to the first usable cert */ if (!private) @@ -1038,7 +1109,10 @@ METHOD(credential_manager_t, get_private, private_key_t*, private = get_private_by_cert(this, cert, type); if (private) { - auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + if (auth) + { + auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + } break; } } @@ -1050,14 +1124,10 @@ METHOD(credential_manager_t, get_private, private_key_t*, METHOD(credential_manager_t, flush_cache, void, private_credential_manager_t *this, certificate_type_t type) { - this->cache->flush(this->cache, type); -} - -METHOD(credential_manager_t, issued_by, bool, - private_credential_manager_t *this, certificate_t *subject, - certificate_t *issuer) -{ - return this->cache->issued_by(this->cache, subject, issuer); + if (this->cache) + { + this->cache->flush(this->cache, type); + } } METHOD(credential_manager_t, add_set, void, @@ -1097,10 +1167,14 @@ METHOD(credential_manager_t, destroy, void, { cache_queue(this); this->cache_queue->destroy(this->cache_queue); - this->sets->remove(this->sets, this->cache, NULL); + if (this->cache) + { + this->sets->remove(this->sets, this->cache, NULL); + this->cache->destroy(this->cache); + } this->sets->destroy(this->sets); this->local_sets->destroy(this->local_sets); - this->cache->destroy(this->cache); + this->exclusive_local_sets->destroy(this->exclusive_local_sets); this->validators->destroy(this->validators); this->lock->destroy(this->lock); this->queue_mutex->destroy(this->queue_mutex); @@ -1137,14 +1211,18 @@ credential_manager_t *credential_manager_create() }, .sets = linked_list_create(), .validators = linked_list_create(), - .cache = cert_cache_create(), .cache_queue = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .queue_mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); - this->sets->insert_first(this->sets, this->cache); + this->exclusive_local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); + if (lib->settings->get_bool(lib->settings, "libstrongswan.cert_cache", TRUE)) + { + this->cache = cert_cache_create(); + this->sets->insert_first(this->sets, this->cache); + } return &this->public; } diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h index 8e8f04b8c..d9a47b7d7 100644 --- a/src/libstrongswan/credentials/credential_manager.h +++ b/src/libstrongswan/credentials/credential_manager.h @@ -89,7 +89,7 @@ struct credential_manager_t { * @param type kind of requested shared key * @param first first subject between key is shared * @param second second subject between key is shared - * @return enumerator over shared keys + * @return enumerator over (shared_key_t*,id_match_t,id_match_t) */ enumerator_t *(*create_shared_enumerator)(credential_manager_t *this, shared_key_type_t type, @@ -204,10 +204,12 @@ struct credential_manager_t { * * @param subject subject certificate to check * @param issuer issuer certificate that potentially has signed subject + * @param scheme receives used signature scheme, if given * @return TRUE if issuer signed subject */ bool (*issued_by)(credential_manager_t *this, - certificate_t *subject, certificate_t *issuer); + certificate_t *subject, certificate_t *issuer, + signature_scheme_t *scheme); /** * Register a credential set to the manager. @@ -230,10 +232,14 @@ struct credential_manager_t { * operation, sets may be added for the calling thread only. This * does not require a write lock and is therefore a much cheaper * operation. + * The exclusive option allows to disable all other credential sets + * until the set is deregistered. * * @param set set to register + * @param exclusive TRUE to disable all other sets for this thread */ - void (*add_local_set)(credential_manager_t *this, credential_set_t *set); + void (*add_local_set)(credential_manager_t *this, credential_set_t *set, + bool exclusive); /** * Unregister a thread local credential set from the manager. diff --git a/src/libstrongswan/credentials/sets/cert_cache.c b/src/libstrongswan/credentials/sets/cert_cache.c index 968c3e31e..a7d0ed8f9 100644 --- a/src/libstrongswan/credentials/sets/cert_cache.c +++ b/src/libstrongswan/credentials/sets/cert_cache.c @@ -46,6 +46,11 @@ struct relation_t { */ certificate_t *issuer; + /** + * Signature scheme used to sign this relation + */ + signature_scheme_t scheme; + /** * Cache hits */ @@ -77,7 +82,8 @@ struct private_cert_cache_t { * Cache relation in a free slot/replace an other */ static void cache(private_cert_cache_t *this, - certificate_t *subject, certificate_t *issuer) + certificate_t *subject, certificate_t *issuer, + signature_scheme_t scheme) { relation_t *rel; int i, offset, try; @@ -95,6 +101,7 @@ static void cache(private_cert_cache_t *this, { rel->subject = subject->get_ref(subject); rel->issuer = issuer->get_ref(issuer); + rel->scheme = scheme; return rel->lock->unlock(rel->lock); } rel->lock->unlock(rel->lock); @@ -123,6 +130,7 @@ static void cache(private_cert_cache_t *this, } rel->subject = subject->get_ref(subject); rel->issuer = issuer->get_ref(issuer); + rel->scheme = scheme; rel->hits = 0; return rel->lock->unlock(rel->lock); } @@ -133,9 +141,11 @@ static void cache(private_cert_cache_t *this, } METHOD(cert_cache_t, issued_by, bool, - private_cert_cache_t *this, certificate_t *subject, certificate_t *issuer) + private_cert_cache_t *this, certificate_t *subject, certificate_t *issuer, + signature_scheme_t *schemep) { relation_t *found = NULL, *current; + signature_scheme_t scheme; int i; for (i = 0; i < CACHE_SIZE; i++) @@ -154,7 +164,11 @@ METHOD(cert_cache_t, issued_by, bool, { /* write hit counter is not locked, but not critical */ current->hits++; - found = current; + found = current;; + if (schemep) + { + *schemep = current->scheme; + } } } } @@ -165,9 +179,13 @@ METHOD(cert_cache_t, issued_by, bool, } } /* no cache hit, check and cache signature */ - if (subject->issued_by(subject, issuer)) + if (subject->issued_by(subject, issuer, &scheme)) { - cache(this, subject, issuer); + cache(this, subject, issuer, scheme); + if (schemep) + { + *schemep = scheme; + } return TRUE; } return FALSE; diff --git a/src/libstrongswan/credentials/sets/cert_cache.h b/src/libstrongswan/credentials/sets/cert_cache.h index d2721866e..2bcdbe464 100644 --- a/src/libstrongswan/credentials/sets/cert_cache.h +++ b/src/libstrongswan/credentials/sets/cert_cache.h @@ -45,10 +45,12 @@ struct cert_cache_t { * * @param subject certificate to verify * @param issuer issuing certificate to verify subject + * @param scheme receives used signature scheme, if given * @return TRUE if subject issued by issuer */ bool (*issued_by)(cert_cache_t *this, - certificate_t *subject, certificate_t *issuer); + certificate_t *subject, certificate_t *issuer, + signature_scheme_t *scheme); /** * Flush the certificate cache. diff --git a/src/libstrongswan/crypto/aead.c b/src/libstrongswan/crypto/aead.c index 51cb05909..02fb8d50a 100644 --- a/src/libstrongswan/crypto/aead.c +++ b/src/libstrongswan/crypto/aead.c @@ -40,26 +40,41 @@ struct private_aead_t { signer_t *signer; }; -METHOD(aead_t, encrypt, void, +METHOD(aead_t, encrypt, bool, private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, chunk_t *encrypted) { chunk_t encr, sig; - this->signer->get_signature(this->signer, assoc, NULL); - this->signer->get_signature(this->signer, iv, NULL); + if (!this->signer->get_signature(this->signer, assoc, NULL) || + !this->signer->get_signature(this->signer, iv, NULL)) + { + return FALSE; + } if (encrypted) { - this->crypter->encrypt(this->crypter, plain, iv, &encr); - this->signer->allocate_signature(this->signer, encr, &sig); + if (!this->crypter->encrypt(this->crypter, plain, iv, &encr)) + { + return FALSE; + } + if (!this->signer->allocate_signature(this->signer, encr, &sig)) + { + free(encr.ptr); + return FALSE; + } *encrypted = chunk_cat("cmm", iv, encr, sig); } else { - this->crypter->encrypt(this->crypter, plain, iv, NULL); - this->signer->get_signature(this->signer, plain, plain.ptr + plain.len); + if (!this->crypter->encrypt(this->crypter, plain, iv, NULL) || + !this->signer->get_signature(this->signer, + plain, plain.ptr + plain.len)) + { + return FALSE; + } } + return TRUE; } METHOD(aead_t, decrypt, bool, @@ -80,15 +95,17 @@ METHOD(aead_t, decrypt, bool, chunk_split(encrypted, "mm", encrypted.len - sig.len, &encrypted, sig.len, &sig); - this->signer->get_signature(this->signer, assoc, NULL); - this->signer->get_signature(this->signer, iv, NULL); + if (!this->signer->get_signature(this->signer, assoc, NULL) || + !this->signer->get_signature(this->signer, iv, NULL)) + { + return FALSE; + } if (!this->signer->verify_signature(this->signer, encrypted, sig)) { DBG1(DBG_LIB, "MAC verification failed"); return FALSE; } - this->crypter->decrypt(this->crypter, encrypted, iv, plain); - return TRUE; + return this->crypter->decrypt(this->crypter, encrypted, iv, plain); } METHOD(aead_t, get_block_size, size_t, @@ -116,7 +133,7 @@ METHOD(aead_t, get_key_size, size_t, this->signer->get_key_size(this->signer); } -METHOD(aead_t, set_key, void, +METHOD(aead_t, set_key, bool, private_aead_t *this, chunk_t key) { chunk_t sig, enc; @@ -124,8 +141,8 @@ METHOD(aead_t, set_key, void, chunk_split(key, "mm", this->signer->get_key_size(this->signer), &sig, this->crypter->get_key_size(this->crypter), &enc); - this->signer->set_key(this->signer, sig); - this->crypter->set_key(this->crypter, enc); + return this->signer->set_key(this->signer, sig) && + this->crypter->set_key(this->crypter, enc); } METHOD(aead_t, destroy, void, diff --git a/src/libstrongswan/crypto/aead.h b/src/libstrongswan/crypto/aead.h index 3f6abb4f9..ec526a3d9 100644 --- a/src/libstrongswan/crypto/aead.h +++ b/src/libstrongswan/crypto/aead.h @@ -45,9 +45,10 @@ struct aead_t { * @param assoc associated data to sign * @param iv initialization vector * @param encrypted allocated encryption result + * @return TRUE if successfully encrypted */ - void (*encrypt)(aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, - chunk_t *encrypted); + bool (*encrypt)(aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, + chunk_t *encrypted) __attribute__((warn_unused_result)); /** * Decrypt and verify data, verify associated data. @@ -98,8 +99,10 @@ struct aead_t { * Set the key for encryption and authentication. * * @param key encryption and authentication key + * @return TRUE if key set successfully */ - void (*set_key)(aead_t *this, chunk_t key); + bool (*set_key)(aead_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroy a aead_t. diff --git a/src/libstrongswan/crypto/crypters/crypter.h b/src/libstrongswan/crypto/crypters/crypter.h index 3bf039681..fe854f53d 100644 --- a/src/libstrongswan/crypto/crypters/crypter.h +++ b/src/libstrongswan/crypto/crypters/crypter.h @@ -90,9 +90,10 @@ struct crypter_t { * @param data data to encrypt * @param iv initializing vector * @param encrypted chunk to allocate encrypted data, or NULL + * @return TRUE if encryption successful */ - void (*encrypt) (crypter_t *this, chunk_t data, chunk_t iv, - chunk_t *encrypted); + bool (*encrypt)(crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *encrypted) __attribute__((warn_unused_result)); /** * Decrypt a chunk of data and allocate space for the decrypted value. @@ -104,9 +105,10 @@ struct crypter_t { * @param data data to decrypt * @param iv initializing vector * @param encrypted chunk to allocate decrypted data, or NULL + * @return TRUE if decryption successful */ - void (*decrypt) (crypter_t *this, chunk_t data, chunk_t iv, - chunk_t *decrypted); + bool (*decrypt)(crypter_t *this, chunk_t data, chunk_t iv, + chunk_t *decrypted) __attribute__((warn_unused_result)); /** * Get the block size of the crypto algorithm. @@ -117,7 +119,7 @@ struct crypter_t { * * @return block size in bytes */ - size_t (*get_block_size) (crypter_t *this); + size_t (*get_block_size)(crypter_t *this); /** * Get the IV size of the crypto algorithm. @@ -135,7 +137,7 @@ struct crypter_t { * * @return key size in bytes */ - size_t (*get_key_size) (crypter_t *this); + size_t (*get_key_size)(crypter_t *this); /** * Set the key. @@ -143,13 +145,15 @@ struct crypter_t { * The length of the key must match get_key_size(). * * @param key key to set + * @return TRUE if key set successfully */ - void (*set_key) (crypter_t *this, chunk_t key); + bool (*set_key)(crypter_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a crypter_t object. */ - void (*destroy) (crypter_t *this); + void (*destroy)(crypter_t *this); }; /** diff --git a/src/libstrongswan/crypto/crypto_factory.c b/src/libstrongswan/crypto/crypto_factory.c index 2d13896d6..3736ae38f 100644 --- a/src/libstrongswan/crypto/crypto_factory.c +++ b/src/libstrongswan/crypto/crypto_factory.c @@ -50,6 +50,7 @@ struct entry_t { hasher_constructor_t create_hasher; prf_constructor_t create_prf; rng_constructor_t create_rng; + nonce_gen_constructor_t create_nonce_gen; dh_constructor_t create_dh; void *create; }; @@ -97,6 +98,11 @@ struct private_crypto_factory_t { */ linked_list_t *rngs; + /** + * registered nonce generators, as entry_t + */ + linked_list_t *nonce_gens; + /** * registered diffie hellman, as entry_t */ @@ -329,34 +335,49 @@ METHOD(crypto_factory_t, create_rng, rng_t*, return NULL; } +METHOD(crypto_factory_t, create_nonce_gen, nonce_gen_t*, + private_crypto_factory_t *this) +{ + enumerator_t *enumerator; + entry_t *entry; + nonce_gen_t *nonce_gen = NULL; + + this->lock->read_lock(this->lock); + enumerator = this->nonce_gens->create_enumerator(this->nonce_gens); + while (enumerator->enumerate(enumerator, &entry)) + { + nonce_gen = entry->create_nonce_gen(); + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return nonce_gen; +} + METHOD(crypto_factory_t, create_dh, diffie_hellman_t*, private_crypto_factory_t *this, diffie_hellman_group_t group, ...) { enumerator_t *enumerator; entry_t *entry; + va_list args; + chunk_t g = chunk_empty, p = chunk_empty; diffie_hellman_t *diffie_hellman = NULL; + if (group == MODP_CUSTOM) + { + va_start(args, group); + g = va_arg(args, chunk_t); + p = va_arg(args, chunk_t); + va_end(args); + } + this->lock->read_lock(this->lock); enumerator = this->dhs->create_enumerator(this->dhs); while (enumerator->enumerate(enumerator, &entry)) { if (entry->algo == group) { - if (group == MODP_CUSTOM) - { - va_list args; - chunk_t g, p; - - va_start(args, group); - g = va_arg(args, chunk_t); - p = va_arg(args, chunk_t); - va_end(args); - diffie_hellman = entry->create_dh(MODP_CUSTOM, g, p); - } - else - { - diffie_hellman = entry->create_dh(group); - } + diffie_hellman = entry->create_dh(group, g, p); if (diffie_hellman) { break; @@ -618,6 +639,33 @@ METHOD(crypto_factory_t, remove_rng, void, this->lock->unlock(this->lock); } +METHOD(crypto_factory_t, add_nonce_gen, void, + private_crypto_factory_t *this, const char *plugin_name, + nonce_gen_constructor_t create) +{ + add_entry(this, this->nonce_gens, 0, plugin_name, 0, create); +} + +METHOD(crypto_factory_t, remove_nonce_gen, void, + private_crypto_factory_t *this, nonce_gen_constructor_t create) +{ + entry_t *entry; + enumerator_t *enumerator; + + this->lock->write_lock(this->lock); + enumerator = this->nonce_gens->create_enumerator(this->nonce_gens); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->create_nonce_gen == create) + { + this->nonce_gens->remove_at(this->nonce_gens, enumerator); + free(entry); + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); +} + METHOD(crypto_factory_t, add_dh, void, private_crypto_factory_t *this, diffie_hellman_group_t group, const char *plugin_name, dh_constructor_t create) @@ -756,7 +804,7 @@ METHOD(crypto_factory_t, create_prf_enumerator, enumerator_t*, } /** - * Filter function to enumerate algorithm, not entry + * Filter function to enumerate group, not entry */ static bool dh_filter(void *n, entry_t **entry, diffie_hellman_group_t *group, void *i2, const char **plugin_name) @@ -773,7 +821,7 @@ METHOD(crypto_factory_t, create_dh_enumerator, enumerator_t*, } /** - * Filter function to enumerate algorithm, not entry + * Filter function to enumerate strength, not entry */ static bool rng_filter(void *n, entry_t **entry, rng_quality_t *quality, void *i2, const char **plugin_name) @@ -788,6 +836,22 @@ METHOD(crypto_factory_t, create_rng_enumerator, enumerator_t*, { return create_enumerator(this, this->rngs, rng_filter); } + +/** + * Filter function to enumerate plugin name, not entry + */ +static bool nonce_gen_filter(void *n, entry_t **entry, const char **plugin_name) +{ + *plugin_name = (*entry)->plugin_name; + return TRUE; +} + +METHOD(crypto_factory_t, create_nonce_gen_enumerator, enumerator_t*, + private_crypto_factory_t *this) +{ + return create_enumerator(this, this->nonce_gens, nonce_gen_filter); +} + METHOD(crypto_factory_t, add_test_vector, void, private_crypto_factory_t *this, transform_type_t type, void *vector) { @@ -820,6 +884,7 @@ METHOD(crypto_factory_t, destroy, void, this->hashers->destroy(this->hashers); this->prfs->destroy(this->prfs); this->rngs->destroy(this->rngs); + this->nonce_gens->destroy(this->nonce_gens); this->dhs->destroy(this->dhs); this->tester->destroy(this->tester); this->lock->destroy(this->lock); @@ -841,6 +906,7 @@ crypto_factory_t *crypto_factory_create() .create_hasher = _create_hasher, .create_prf = _create_prf, .create_rng = _create_rng, + .create_nonce_gen = _create_nonce_gen, .create_dh = _create_dh, .add_crypter = _add_crypter, .remove_crypter = _remove_crypter, @@ -854,6 +920,8 @@ crypto_factory_t *crypto_factory_create() .remove_prf = _remove_prf, .add_rng = _add_rng, .remove_rng = _remove_rng, + .add_nonce_gen = _add_nonce_gen, + .remove_nonce_gen = _remove_nonce_gen, .add_dh = _add_dh, .remove_dh = _remove_dh, .create_crypter_enumerator = _create_crypter_enumerator, @@ -863,6 +931,7 @@ crypto_factory_t *crypto_factory_create() .create_prf_enumerator = _create_prf_enumerator, .create_dh_enumerator = _create_dh_enumerator, .create_rng_enumerator = _create_rng_enumerator, + .create_nonce_gen_enumerator = _create_nonce_gen_enumerator, .add_test_vector = _add_test_vector, .destroy = _destroy, }, @@ -872,6 +941,7 @@ crypto_factory_t *crypto_factory_create() .hashers = linked_list_create(), .prfs = linked_list_create(), .rngs = linked_list_create(), + .nonce_gens = linked_list_create(), .dhs = linked_list_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .tester = crypto_tester_create(), diff --git a/src/libstrongswan/crypto/crypto_factory.h b/src/libstrongswan/crypto/crypto_factory.h index 8e5db6355..611ca0bbb 100644 --- a/src/libstrongswan/crypto/crypto_factory.h +++ b/src/libstrongswan/crypto/crypto_factory.h @@ -30,6 +30,7 @@ typedef struct crypto_factory_t crypto_factory_t; #include #include #include +#include #include #include @@ -65,6 +66,11 @@ typedef prf_t* (*prf_constructor_t)(pseudo_random_function_t algo); */ typedef rng_t* (*rng_constructor_t)(rng_quality_t quality); +/** + * Constructor function for nonce generators + */ +typedef nonce_gen_t* (*nonce_gen_constructor_t)(); + /** * Constructor function for diffie hellman * @@ -131,6 +137,13 @@ struct crypto_factory_t { */ rng_t* (*create_rng)(crypto_factory_t *this, rng_quality_t quality); + /** + * Create a nonce generator instance. + * + * @return nonce_gen_t instance, NULL if not supported + */ + nonce_gen_t* (*create_nonce_gen)(crypto_factory_t *this); + /** * Create a diffie hellman instance. * @@ -252,6 +265,23 @@ struct crypto_factory_t { */ void (*remove_rng)(crypto_factory_t *this, rng_constructor_t create); + /** + * Register a nonce generator. + * + * @param plugin_name plugin that registered this algorithm + * @param create constructor function for that nonce generator + */ + void (*add_nonce_gen)(crypto_factory_t *this, const char *plugin_name, + nonce_gen_constructor_t create); + + /** + * Unregister a nonce generator. + * + * @param create constructor function to unregister + */ + void (*remove_nonce_gen)(crypto_factory_t *this, + nonce_gen_constructor_t create); + /** * Register a diffie hellman constructor. * @@ -273,52 +303,59 @@ struct crypto_factory_t { /** * Create an enumerator over all registered crypter algorithms. * - * @return enumerator over encryption_algorithm_t + * @return enumerator over encryption_algorithm_t, plugin */ enumerator_t* (*create_crypter_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered aead algorithms. * - * @return enumerator over encryption_algorithm_t + * @return enumerator over encryption_algorithm_t, plugin */ enumerator_t* (*create_aead_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered signer algorithms. * - * @return enumerator over integrity_algorithm_t + * @return enumerator over integrity_algorithm_t, plugin */ enumerator_t* (*create_signer_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered hasher algorithms. * - * @return enumerator over hash_algorithm_t + * @return enumerator over hash_algorithm_t, plugin */ enumerator_t* (*create_hasher_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered PRFs. * - * @return enumerator over pseudo_random_function_t + * @return enumerator over pseudo_random_function_t, plugin */ enumerator_t* (*create_prf_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered diffie hellman groups. * - * @return enumerator over diffie_hellman_group_t + * @return enumerator over diffie_hellman_group_t, plugin */ enumerator_t* (*create_dh_enumerator)(crypto_factory_t *this); /** * Create an enumerator over all registered random generators. * - * @return enumerator over rng_quality_t + * @return enumerator over rng_quality_t, plugin */ enumerator_t* (*create_rng_enumerator)(crypto_factory_t *this); + /** + * Create an enumerator over all registered nonce generators. + * + * @return enumerator over plugin + */ + enumerator_t* (*create_nonce_gen_enumerator)(crypto_factory_t *this); + /** * Add a test vector to the crypto factory. * diff --git a/src/libstrongswan/crypto/crypto_tester.c b/src/libstrongswan/crypto/crypto_tester.c index 8b1daa885..01e84a133 100644 --- a/src/libstrongswan/crypto/crypto_tester.c +++ b/src/libstrongswan/crypto/crypto_tester.c @@ -151,7 +151,10 @@ static u_int bench_crypter(private_crypto_tester_t *this, memset(iv, 0x56, sizeof(iv)); memset(key, 0x12, sizeof(key)); - crypter->set_key(crypter, chunk_from_thing(key)); + if (!crypter->set_key(crypter, chunk_from_thing(key))) + { + return 0; + } buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -160,10 +163,14 @@ static u_int bench_crypter(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL); - runs++; - crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL); - runs++; + if (crypter->encrypt(crypter, buf, chunk_from_thing(iv), NULL)) + { + runs++; + } + if (crypter->decrypt(crypter, buf, chunk_from_thing(iv), NULL)) + { + runs++; + } } free(buf.ptr); crypter->destroy(crypter); @@ -186,7 +193,7 @@ METHOD(crypto_tester_t, test_crypter, bool, while (enumerator->enumerate(enumerator, &vector)) { crypter_t *crypter; - chunk_t key, plain, cipher, iv; + chunk_t key, iv, plain = chunk_empty, cipher = chunk_empty; if (vector->alg != alg) { @@ -196,53 +203,69 @@ METHOD(crypto_tester_t, test_crypter, bool, { /* test only vectors with a specific key size, if key size given */ continue; } + + tested++; + failed = TRUE; crypter = create(alg, vector->key_size); if (!crypter) { DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported", encryption_algorithm_names, alg, plugin_name, BITS_PER_BYTE * vector->key_size); - failed = TRUE; continue; } - failed = FALSE; - tested++; - key = chunk_create(vector->key, crypter->get_key_size(crypter)); - crypter->set_key(crypter, key); + if (!crypter->set_key(crypter, key)) + { + goto failure; + } iv = chunk_create(vector->iv, crypter->get_iv_size(crypter)); /* allocated encryption */ plain = chunk_create(vector->plain, vector->len); - crypter->encrypt(crypter, plain, iv, &cipher); + if (!crypter->encrypt(crypter, plain, iv, &cipher)) + { + goto failure; + } if (!memeq(vector->cipher, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } /* inline decryption */ - crypter->decrypt(crypter, cipher, iv, NULL); + if (!crypter->decrypt(crypter, cipher, iv, NULL)) + { + goto failure; + } if (!memeq(vector->plain, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } - free(cipher.ptr); /* allocated decryption */ - cipher = chunk_create(vector->cipher, vector->len); - crypter->decrypt(crypter, cipher, iv, &plain); + if (!crypter->decrypt(crypter, + chunk_create(vector->cipher, vector->len), iv, &plain)) + { + goto failure; + } if (!memeq(vector->plain, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } /* inline encryption */ - crypter->encrypt(crypter, plain, iv, NULL); + if (!crypter->encrypt(crypter, plain, iv, NULL)) + { + goto failure; + } if (!memeq(vector->cipher, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } - free(plain.ptr); + failed = FALSE; +failure: crypter->destroy(crypter); + chunk_free(&cipher); + chunk_free(&plain); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -306,7 +329,10 @@ static u_int bench_aead(private_crypto_tester_t *this, memset(iv, 0x56, sizeof(iv)); memset(key, 0x12, sizeof(key)); memset(assoc, 0x78, sizeof(assoc)); - aead->set_key(aead, chunk_from_thing(key)); + if (!aead->set_key(aead, chunk_from_thing(key))) + { + return 0; + } icv = aead->get_icv_size(aead); buf = chunk_alloc(this->bench_size + icv); @@ -317,12 +343,16 @@ static u_int bench_aead(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - aead->encrypt(aead, buf, chunk_from_thing(assoc), - chunk_from_thing(iv), NULL); - runs += 2; - aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv), - chunk_from_thing(assoc), chunk_from_thing(iv), NULL); - runs += 2; + if (aead->encrypt(aead, buf, chunk_from_thing(assoc), + chunk_from_thing(iv), NULL)) + { + runs += 2; + } + if (aead->decrypt(aead, chunk_create(buf.ptr, buf.len + icv), + chunk_from_thing(assoc), chunk_from_thing(iv), NULL)) + { + runs += 2; + } } free(buf.ptr); aead->destroy(aead); @@ -345,7 +375,7 @@ METHOD(crypto_tester_t, test_aead, bool, while (enumerator->enumerate(enumerator, &vector)) { aead_t *aead; - chunk_t key, plain, cipher, iv, assoc; + chunk_t key, iv, assoc, plain = chunk_empty, cipher = chunk_empty; size_t icv; if (vector->alg != alg) @@ -356,63 +386,72 @@ METHOD(crypto_tester_t, test_aead, bool, { /* test only vectors with a specific key size, if key size given */ continue; } + + tested++; + failed = TRUE; aead = create(alg, vector->key_size); if (!aead) { DBG1(DBG_LIB, "%N[%s]: %u bit key size not supported", encryption_algorithm_names, alg, plugin_name, BITS_PER_BYTE * vector->key_size); - failed = TRUE; continue; } - failed = FALSE; - tested++; - key = chunk_create(vector->key, aead->get_key_size(aead)); - aead->set_key(aead, key); + if (!aead->set_key(aead, key)) + { + goto failure; + } iv = chunk_create(vector->iv, aead->get_iv_size(aead)); assoc = chunk_create(vector->adata, vector->alen); icv = aead->get_icv_size(aead); /* allocated encryption */ plain = chunk_create(vector->plain, vector->len); - aead->encrypt(aead, plain, assoc, iv, &cipher); + if (!aead->encrypt(aead, plain, assoc, iv, &cipher)) + { + goto failure; + } if (!memeq(vector->cipher, cipher.ptr, cipher.len)) { - failed = TRUE; + goto failure; } /* inline decryption */ if (!aead->decrypt(aead, cipher, assoc, iv, NULL)) { - failed = TRUE; + goto failure; } if (!memeq(vector->plain, cipher.ptr, cipher.len - icv)) { - failed = TRUE; + goto failure; } - free(cipher.ptr); /* allocated decryption */ - cipher = chunk_create(vector->cipher, vector->len + icv); - if (!aead->decrypt(aead, cipher, assoc, iv, &plain)) + if (!aead->decrypt(aead, chunk_create(vector->cipher, vector->len + icv), + assoc, iv, &plain)) { - plain = chunk_empty; - failed = TRUE; + goto failure; } - else if (!memeq(vector->plain, plain.ptr, plain.len)) + if (!memeq(vector->plain, plain.ptr, plain.len)) { - failed = TRUE; + goto failure; } plain.ptr = realloc(plain.ptr, plain.len + icv); /* inline encryption */ - aead->encrypt(aead, plain, assoc, iv, NULL); + if (!aead->encrypt(aead, plain, assoc, iv, NULL)) + { + goto failure; + } if (!memeq(vector->cipher, plain.ptr, plain.len + icv)) { - failed = TRUE; + goto failure; } - free(plain.ptr); + failed = FALSE; +failure: aead->destroy(aead); + chunk_free(&cipher); + chunk_free(&plain); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -458,7 +497,7 @@ METHOD(crypto_tester_t, test_aead, bool, * Benchmark a signer */ static u_int bench_signer(private_crypto_tester_t *this, - encryption_algorithm_t alg, signer_constructor_t create) + integrity_algorithm_t alg, signer_constructor_t create) { signer_t *signer; @@ -472,7 +511,10 @@ static u_int bench_signer(private_crypto_tester_t *this, u_int runs; memset(key, 0x12, sizeof(key)); - signer->set_key(signer, chunk_from_thing(key)); + if (!signer->set_key(signer, chunk_from_thing(key))) + { + return 0; + } buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -481,10 +523,14 @@ static u_int bench_signer(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - signer->get_signature(signer, buf, mac); - runs++; - signer->verify_signature(signer, buf, chunk_from_thing(mac)); - runs++; + if (signer->get_signature(signer, buf, mac)) + { + runs++; + } + if (signer->verify_signature(signer, buf, chunk_from_thing(mac))) + { + runs++; + } } free(buf.ptr); signer->destroy(signer); @@ -507,7 +553,7 @@ METHOD(crypto_tester_t, test_signer, bool, while (enumerator->enumerate(enumerator, &vector)) { signer_t *signer; - chunk_t key, data, mac; + chunk_t key, data, mac = chunk_empty; if (vector->alg != alg) { @@ -515,63 +561,79 @@ METHOD(crypto_tester_t, test_signer, bool, } tested++; + failed = TRUE; signer = create(alg); if (!signer) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", integrity_algorithm_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - key = chunk_create(vector->key, signer->get_key_size(signer)); - signer->set_key(signer, key); - + if (!signer->set_key(signer, key)) + { + goto failure; + } /* allocated signature */ data = chunk_create(vector->data, vector->len); - signer->allocate_signature(signer, data, &mac); + if (!signer->allocate_signature(signer, data, &mac)) + { + goto failure; + } if (mac.len != signer->get_block_size(signer)) { - failed = TRUE; + goto failure; } if (!memeq(vector->mac, mac.ptr, mac.len)) { - failed = TRUE; + goto failure; } /* signature to existing buffer */ memset(mac.ptr, 0, mac.len); - signer->get_signature(signer, data, mac.ptr); + if (!signer->get_signature(signer, data, mac.ptr)) + { + goto failure; + } if (!memeq(vector->mac, mac.ptr, mac.len)) { - failed = TRUE; + goto failure; } /* signature verification, good case */ if (!signer->verify_signature(signer, data, mac)) { - failed = TRUE; + goto failure; } /* signature verification, bad case */ *(mac.ptr + mac.len - 1) += 1; if (signer->verify_signature(signer, data, mac)) { - failed = TRUE; + goto failure; } /* signature to existing buffer, using append mode */ if (data.len > 2) { - signer->allocate_signature(signer, chunk_create(data.ptr, 1), NULL); - signer->get_signature(signer, chunk_create(data.ptr + 1, 1), NULL); + if (!signer->allocate_signature(signer, + chunk_create(data.ptr, 1), NULL)) + { + goto failure; + } + if (!signer->get_signature(signer, + chunk_create(data.ptr + 1, 1), NULL)) + { + goto failure; + } if (!signer->verify_signature(signer, chunk_skip(data, 2), chunk_create(vector->mac, mac.len))) { - failed = TRUE; + goto failure; } } - free(mac.ptr); + failed = FALSE; +failure: signer->destroy(signer); + chunk_free(&mac); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -627,8 +689,10 @@ static u_int bench_hasher(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - hasher->get_hash(hasher, buf, hash); - runs++; + if (hasher->get_hash(hasher, buf, hash)) + { + runs++; + } } free(buf.ptr); hasher->destroy(hasher); @@ -659,50 +723,73 @@ METHOD(crypto_tester_t, test_hasher, bool, } tested++; + failed = TRUE; hasher = create(alg); if (!hasher) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", hash_algorithm_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - /* allocated hash */ data = chunk_create(vector->data, vector->len); - hasher->allocate_hash(hasher, data, &hash); + if (!hasher->allocate_hash(hasher, data, &hash)) + { + goto failure; + } if (hash.len != hasher->get_hash_size(hasher)) { - failed = TRUE; + goto failure; } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } - /* hash to existing buffer */ + /* hash to existing buffer, with a reset */ memset(hash.ptr, 0, hash.len); - hasher->get_hash(hasher, data, hash.ptr); + if (!hasher->get_hash(hasher, data, NULL)) + { + goto failure; + } + if (!hasher->reset(hasher)) + { + goto failure; + } + if (!hasher->get_hash(hasher, data, hash.ptr)) + { + goto failure; + } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } /* hasher to existing buffer, using append mode */ if (data.len > 2) { memset(hash.ptr, 0, hash.len); - hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL); - hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL); - hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr); + if (!hasher->allocate_hash(hasher, chunk_create(data.ptr, 1), NULL)) + { + goto failure; + } + if (!hasher->get_hash(hasher, chunk_create(data.ptr + 1, 1), NULL)) + { + goto failure; + } + if (!hasher->get_hash(hasher, chunk_skip(data, 2), hash.ptr)) + { + goto failure; + } if (!memeq(vector->hash, hash.ptr, hash.len)) { - failed = TRUE; + goto failure; } } - free(hash.ptr); + failed = FALSE; +failure: hasher->destroy(hasher); + chunk_free(&hash); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -746,11 +833,18 @@ static u_int bench_prf(private_crypto_tester_t *this, prf = create(alg); if (prf) { - char bytes[prf->get_block_size(prf)]; + char bytes[prf->get_block_size(prf)], key[prf->get_block_size(prf)]; chunk_t buf; struct timespec start; u_int runs; + memset(key, 0x56, prf->get_block_size(prf)); + if (!prf->set_key(prf, chunk_create(key, prf->get_block_size(prf)))) + { + prf->destroy(prf); + return 0; + } + buf = chunk_alloc(this->bench_size); memset(buf.ptr, 0x34, buf.len); @@ -758,8 +852,10 @@ static u_int bench_prf(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - prf->get_bytes(prf, buf, bytes); - runs++; + if (prf->get_bytes(prf, buf, bytes)) + { + runs++; + } } free(buf.ptr); prf->destroy(prf); @@ -782,7 +878,7 @@ METHOD(crypto_tester_t, test_prf, bool, while (enumerator->enumerate(enumerator, &vector)) { prf_t *prf; - chunk_t key, seed, out; + chunk_t key, seed, out = chunk_empty; if (vector->alg != alg) { @@ -790,41 +886,50 @@ METHOD(crypto_tester_t, test_prf, bool, } tested++; + failed = TRUE; prf = create(alg); if (!prf) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", pseudo_random_function_names, alg, plugin_name); - failed = TRUE; break; } - failed = FALSE; - key = chunk_create(vector->key, vector->key_size); - prf->set_key(prf, key); - + if (!prf->set_key(prf, key)) + { + goto failure; + } /* allocated bytes */ seed = chunk_create(vector->seed, vector->len); - prf->allocate_bytes(prf, seed, &out); + if (!prf->allocate_bytes(prf, seed, &out)) + { + goto failure; + } if (out.len != prf->get_block_size(prf)) { - failed = TRUE; + goto failure; } if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } /* bytes to existing buffer */ memset(out.ptr, 0, out.len); if (vector->stateful) { - prf->set_key(prf, key); + if (!prf->set_key(prf, key)) + { + goto failure; + } + } + if (!prf->get_bytes(prf, seed, out.ptr)) + { + goto failure; } - prf->get_bytes(prf, seed, out.ptr); if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } /* bytes to existing buffer, using append mode */ if (seed.len > 2) @@ -832,19 +937,33 @@ METHOD(crypto_tester_t, test_prf, bool, memset(out.ptr, 0, out.len); if (vector->stateful) { - prf->set_key(prf, key); + if (!prf->set_key(prf, key)) + { + goto failure; + } + } + if (!prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL)) + { + goto failure; + } + if (!prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL)) + { + goto failure; + } + if (!prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr)) + { + goto failure; } - prf->allocate_bytes(prf, chunk_create(seed.ptr, 1), NULL); - prf->get_bytes(prf, chunk_create(seed.ptr + 1, 1), NULL); - prf->get_bytes(prf, chunk_skip(seed, 2), out.ptr); if (!memeq(vector->out, out.ptr, out.len)) { - failed = TRUE; + goto failure; } } - free(out.ptr); + failed = FALSE; +failure: prf->destroy(prf); + chunk_free(&out); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", @@ -897,7 +1016,11 @@ static u_int bench_rng(private_crypto_tester_t *this, start_timing(&start); while (end_timing(&start) < this->bench_time) { - rng->get_bytes(rng, buf.len, buf.ptr); + if (!rng->get_bytes(rng, buf.len, buf.ptr)) + { + runs = 0; + break; + } runs++; } free(buf.ptr); @@ -927,8 +1050,8 @@ METHOD(crypto_tester_t, test_rng, bool, enumerator = this->rng->create_enumerator(this->rng); while (enumerator->enumerate(enumerator, &vector)) { + chunk_t data = chunk_empty; rng_t *rng; - chunk_t data; if (vector->quality != quality) { @@ -936,37 +1059,37 @@ METHOD(crypto_tester_t, test_rng, bool, } tested++; + failed = TRUE; rng = create(quality); if (!rng) { DBG1(DBG_LIB, "disabled %N[%s]: creating instance failed", rng_quality_names, quality, plugin_name); - failed = TRUE; break; } - failed = FALSE; - /* allocated bytes */ - rng->allocate_bytes(rng, vector->len, &data); - if (data.len != vector->len) + if (!rng->allocate_bytes(rng, vector->len, &data) || + data.len != vector->len || + !vector->test(vector->user, data)) { - failed = TRUE; + goto failure; } - if (!vector->test(vector->user, data)) + /* write bytes into existing buffer */ + memset(data.ptr, 0, data.len); + if (!rng->get_bytes(rng, vector->len, data.ptr)) { - failed = TRUE; + goto failure; } - /* bytes to existing buffer */ - memset(data.ptr, 0, data.len); - rng->get_bytes(rng, vector->len, data.ptr); if (!vector->test(vector->user, data)) { - failed = TRUE; + goto failure; } - free(data.ptr); + failed = FALSE; +failure: rng->destroy(rng); + chunk_free(&data); if (failed) { DBG1(DBG_LIB, "disabled %N[%s]: %s test vector failed", diff --git a/src/libstrongswan/crypto/hashers/hasher.c b/src/libstrongswan/crypto/hashers/hasher.c index 81750a519..dc73d5223 100644 --- a/src/libstrongswan/crypto/hashers/hasher.c +++ b/src/libstrongswan/crypto/hashers/hasher.c @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi - * + * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -32,6 +32,19 @@ ENUM(hash_algorithm_names, HASH_UNKNOWN, HASH_SHA512, "HASH_SHA512" ); +ENUM(hash_algorithm_short_names, HASH_UNKNOWN, HASH_SHA512, + "unknown", + "preferred", + "md2", + "md4", + "md5", + "sha1", + "sha224", + "sha256", + "sha384", + "sha512" +); + /* * Described in header. */ @@ -65,6 +78,105 @@ hash_algorithm_t hasher_algorithm_from_oid(int oid) } } +/* + * Described in header. + */ +hash_algorithm_t hasher_algorithm_from_prf(pseudo_random_function_t alg) +{ + switch (alg) + { + case PRF_HMAC_MD5: + return HASH_MD5; + case PRF_HMAC_SHA1: + case PRF_FIPS_SHA1_160: + case PRF_KEYED_SHA1: + return HASH_SHA1; + case PRF_HMAC_SHA2_256: + return HASH_SHA256; + case PRF_HMAC_SHA2_384: + return HASH_SHA384; + case PRF_HMAC_SHA2_512: + return HASH_SHA512; + case PRF_HMAC_TIGER: + case PRF_AES128_XCBC: + case PRF_AES128_CMAC: + case PRF_FIPS_DES: + case PRF_CAMELLIA128_XCBC: + case PRF_UNDEFINED: + break; + } + return HASH_UNKNOWN; +} + +/* + * Described in header. + */ +hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, + size_t *length) +{ + if (length) + { + switch (alg) + { + case AUTH_HMAC_MD5_96: + case AUTH_HMAC_SHA1_96: + case AUTH_HMAC_SHA2_256_96: + *length = 12; + break; + case AUTH_HMAC_MD5_128: + case AUTH_HMAC_SHA1_128: + case AUTH_HMAC_SHA2_256_128: + *length = 16; + break; + case AUTH_HMAC_SHA1_160: + *length = 20; + break; + case AUTH_HMAC_SHA2_384_192: + *length = 24; + break; + case AUTH_HMAC_SHA2_256_256: + case AUTH_HMAC_SHA2_512_256: + *length = 32; + break; + case AUTH_HMAC_SHA2_384_384: + *length = 48; + break; + default: + break; + } + } + switch (alg) + { + case AUTH_HMAC_MD5_96: + case AUTH_HMAC_MD5_128: + case AUTH_KPDK_MD5: + return HASH_MD5; + case AUTH_HMAC_SHA1_96: + case AUTH_HMAC_SHA1_128: + case AUTH_HMAC_SHA1_160: + return HASH_SHA1; + case AUTH_HMAC_SHA2_256_96: + case AUTH_HMAC_SHA2_256_128: + case AUTH_HMAC_SHA2_256_256: + return HASH_SHA256; + case AUTH_HMAC_SHA2_384_192: + case AUTH_HMAC_SHA2_384_384: + return HASH_SHA384; + case AUTH_HMAC_SHA2_512_256: + return HASH_SHA512; + case AUTH_AES_CMAC_96: + case AUTH_AES_128_GMAC: + case AUTH_AES_192_GMAC: + case AUTH_AES_256_GMAC: + case AUTH_AES_XCBC_96: + case AUTH_DES_MAC: + case AUTH_CAMELLIA_XCBC_96: + case AUTH_UNDEFINED: + break; + } + return HASH_UNKNOWN; +} + /* * Described in header. */ diff --git a/src/libstrongswan/crypto/hashers/hasher.h b/src/libstrongswan/crypto/hashers/hasher.h index 9fa043c7e..759f6a23c 100644 --- a/src/libstrongswan/crypto/hashers/hasher.h +++ b/src/libstrongswan/crypto/hashers/hasher.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi - * + * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ typedef enum hash_algorithm_t hash_algorithm_t; typedef struct hasher_t hasher_t; #include +#include +#include #include /** @@ -61,10 +63,16 @@ enum hash_algorithm_t { */ extern enum_name_t *hash_algorithm_names; +/** + * Short names for hash_algorithm_names + */ +extern enum_name_t *hash_algorithm_short_names; + /** * Generic interface for all hash functions. */ struct hasher_t { + /** * Hash data and write it in the buffer. * @@ -77,8 +85,10 @@ struct hasher_t { * * @param data data to hash * @param hash pointer where the hash will be written + * @return TRUE if hash created successfully */ - void (*get_hash) (hasher_t *this, chunk_t data, u_int8_t *hash); + bool (*get_hash)(hasher_t *this, chunk_t data, + u_int8_t *hash) __attribute__((warn_unused_result)); /** * Hash data and allocate space for the hash. @@ -89,35 +99,60 @@ struct hasher_t { * * @param data chunk with data to hash * @param hash chunk which will hold allocated hash + * @return TRUE if hash allocated successfully */ - void (*allocate_hash) (hasher_t *this, chunk_t data, chunk_t *hash); + bool (*allocate_hash)(hasher_t *this, chunk_t data, + chunk_t *hash) __attribute__((warn_unused_result)); /** * Get the size of the resulting hash. * * @return hash size in bytes */ - size_t (*get_hash_size) (hasher_t *this); + size_t (*get_hash_size)(hasher_t *this); /** - * Resets the hashers state. + * Resets the hasher's state. + * + * @return TRUE if hasher reset successfully */ - void (*reset) (hasher_t *this); + bool (*reset)(hasher_t *this) __attribute__((warn_unused_result)); /** * Destroys a hasher object. */ - void (*destroy) (hasher_t *this); + void (*destroy)(hasher_t *this); }; /** * Conversion of ASN.1 OID to hash algorithm. * * @param oid ASN.1 OID - * @return hash algorithm, HASH_UNKNOWN if OID unsuported + * @return hash algorithm, HASH_UNKNOWN if OID unsupported */ hash_algorithm_t hasher_algorithm_from_oid(int oid); +/** + * Conversion of PRF algorithm to hash algorithm (if based on one). + * + * @param alg prf algorithm + * @return hash algorithm, HASH_UNKNOWN if not based on a hash + */ +hash_algorithm_t hasher_algorithm_from_prf(pseudo_random_function_t alg); + +/** + * Conversion of integrity algorithm to hash algorithm (if based on one). + * + * If length is not NULL the length of the resulting signature is returned, + * which might be smaller than the output size of the underlying hash. + * + * @param alg integrity algorithm + * @param length returns signature length, if not NULL + * @return hash algorithm, HASH_UNKNOWN if not based on a hash + */ +hash_algorithm_t hasher_algorithm_from_integrity(integrity_algorithm_t alg, + size_t *length); + /** * Conversion of hash algorithm into ASN.1 OID. * diff --git a/src/libstrongswan/crypto/mac.h b/src/libstrongswan/crypto/mac.h new file mode 100644 index 000000000..f7b43ba39 --- /dev/null +++ b/src/libstrongswan/crypto/mac.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mac mac + * @{ @ingroup crypto + */ + +#ifndef MAC_H_ +#define MAC_H_ + +typedef struct mac_t mac_t; + +#include + +/** + * Generic interface for message authentication codes. + * + * Classes implementing this interface can use the PRF and signer wrappers. + */ +struct mac_t { + + /** + * Generate message authentication code. + * + * If out is NULL, no result is given back. A next call will + * append the data to already supplied data. If out is not NULL, + * the mac of all apended data is calculated, written to out and the + * internal state is reset. + * + * @param data chunk of data to authenticate + * @param out pointer where the generated bytes will be written + * @return TRUE if mac generated successfully + */ + bool (*get_mac)(mac_t *this, chunk_t data, + u_int8_t *out) __attribute__((warn_unused_result)); + + /** + * Get the size of the resulting MAC. + * + * @return block size in bytes + */ + size_t (*get_mac_size)(mac_t *this); + + /** + * Set the key to be used for the MAC. + * + * Any key length must be accepted. + * + * @param key key to set + * @return TRUE if key set successfully + */ + bool (*set_key)(mac_t *this, + chunk_t key) __attribute__((warn_unused_result)); + + /** + * Destroys a mac_t object. + */ + void (*destroy) (mac_t *this); +}; + +#endif /** MAC_H_ @}*/ diff --git a/src/libstrongswan/crypto/nonce_gen.h b/src/libstrongswan/crypto/nonce_gen.h new file mode 100644 index 000000000..50f3c0090 --- /dev/null +++ b/src/libstrongswan/crypto/nonce_gen.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nonce_gen nonce_gen + * @{ @ingroup crypto + */ + +#ifndef NONCE_GEN_H_ +#define NONCE_GEN_H_ + +typedef struct nonce_gen_t nonce_gen_t; + +#include + +/** + * Generic interface for nonce generators. + */ +struct nonce_gen_t { + + /** + * Generates a nonce and writes it into the buffer. + * + * @param size size of nonce in bytes + * @param buffer pointer where the generated nonce will be written + * @return TRUE if nonce allocation was succesful, FALSE otherwise + */ + bool (*get_nonce)(nonce_gen_t *this, size_t size, + u_int8_t *buffer) __attribute__((warn_unused_result)); + + /** + * Generates a nonce and allocates space for it. + * + * @param size size of nonce in bytes + * @param chunk chunk which will hold the generated nonce + * @return TRUE if nonce allocation was succesful, FALSE otherwise + */ + bool (*allocate_nonce)(nonce_gen_t *this, size_t size, + chunk_t *chunk) __attribute__((warn_unused_result)); + + /** + * Destroys a nonce generator object. + */ + void (*destroy)(nonce_gen_t *this); +}; + +#endif /** NONCE_GEN_H_ @}*/ diff --git a/src/libstrongswan/crypto/pkcs7.c b/src/libstrongswan/crypto/pkcs7.c new file mode 100644 index 000000000..0ec19f2cd --- /dev/null +++ b/src/libstrongswan/crypto/pkcs7.c @@ -0,0 +1,1061 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2002-2008 Andreas Steffen + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pkcs7.h" + +typedef struct private_pkcs7_t private_pkcs7_t; + +/** + * Private data of a pkcs7_t object. + */ +struct private_pkcs7_t { + /** + * Public interface for this certificate. + */ + pkcs7_t public; + + /** + * contentInfo type + */ + int type; + + /** + * ASN.1 encoded content + */ + chunk_t content; + + /** + * ASN.1 parsing start level + */ + u_int level; + + /** + * retrieved data + */ + chunk_t data; + + /** + * ASN.1 encoded attributes + */ + pkcs9_t *attributes; + + /** + * Linked list of X.509 certificates + */ + linked_list_t *certs; +}; + +METHOD(pkcs7_t, is_data, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_DATA; +} + +METHOD(pkcs7_t, is_signedData, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_SIGNED_DATA; +} + +METHOD(pkcs7_t, is_envelopedData, bool, + private_pkcs7_t *this) +{ + return this->type == OID_PKCS7_ENVELOPED_DATA; +} + +/** + * ASN.1 definition of the PKCS#7 ContentInfo type + */ +static const asn1Object_t contentInfoObjects[] = { + { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */ + { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_BODY }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_INFO_TYPE 1 +#define PKCS7_INFO_CONTENT 2 + +/** + * Parse PKCS#7 contentInfo object + */ +static bool parse_contentInfo(private_pkcs7_t *this) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID; + bool success = FALSE; + + if (!this->data.ptr) + { + return FALSE; + } + + parser = asn1_parser_create(contentInfoObjects, this->data); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + if (objectID == PKCS7_INFO_TYPE) + { + this->type = asn1_known_oid(object); + if (this->type < OID_PKCS7_DATA || + this->type > OID_PKCS7_ENCRYPTED_DATA) + { + DBG1(DBG_LIB, "unknown pkcs7 content type"); + goto end; + } + } + else if (objectID == PKCS7_INFO_CONTENT && object.len > 0) + { + chunk_free(&this->content); + this->content = chunk_clone(object); + } + } + success = parser->success(parser); + + if (success) + { + this->level += 2; + chunk_free(&this->data); + } + +end: + parser->destroy(parser); + return success; +} + +/** + * Check whether to abort the requested parsing + */ +static bool abort_parsing(private_pkcs7_t *this, int type) +{ + if (this->type != type) + { + DBG1(DBG_LIB, "pkcs7 content to be parsed is not of type '%s'", + oid_names[type].name); + return TRUE; + } + return FALSE; +} + +METHOD(pkcs7_t, parse_data, bool, + private_pkcs7_t *this) +{ + chunk_t data; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_DATA)) + { + return FALSE; + } + data = this->content; + if (data.len == 0) + { + this->data = chunk_empty; + return TRUE; + } + if (asn1_parse_simple_object(&data, ASN1_OCTET_STRING, + this->level, "data")) + { + this->data = chunk_clone(data); + return TRUE; + } + return FALSE; +} + +/** + * ASN.1 definition of the PKCS#7 signedData type + */ +static const asn1Object_t signedDataObjects[] = { + { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ + { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ + { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_LOOP }, /* 6 */ + { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ + { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT | + ASN1_LOOP }, /* 9 */ + { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ + { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ + { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ + { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ + { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ + { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ + { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ + { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ + { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT | + ASN1_OBJ }, /* 19 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ + { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ + { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ + { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ + { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_SIGNED_VERSION 1 +#define PKCS7_DIGEST_ALG 3 +#define PKCS7_SIGNED_CONTENT_INFO 5 +#define PKCS7_SIGNED_CERT 7 +#define PKCS7_SIGNER_INFO 13 +#define PKCS7_SIGNER_INFO_VERSION 14 +#define PKCS7_SIGNED_ISSUER 16 +#define PKCS7_SIGNED_SERIAL_NUMBER 17 +#define PKCS7_DIGEST_ALGORITHM 18 +#define PKCS7_AUTH_ATTRIBUTES 19 +#define PKCS7_DIGEST_ENC_ALGORITHM 21 +#define PKCS7_ENCRYPTED_DIGEST 22 + +METHOD(pkcs7_t, parse_signedData, bool, + private_pkcs7_t *this, certificate_t *cacert) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID, version; + int digest_alg = OID_UNKNOWN; + int enc_alg = OID_UNKNOWN; + int signerInfos = 0; + bool success = FALSE; + + chunk_t encrypted_digest = chunk_empty; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_SIGNED_DATA)) + { + return FALSE; + } + + parser = asn1_parser_create(signedDataObjects, this->content); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser); + + switch (objectID) + { + case PKCS7_SIGNED_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + break; + case PKCS7_DIGEST_ALG: + digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_SIGNED_CONTENT_INFO: + { + pkcs7_t *data = pkcs7_create_from_chunk(object, level+1); + + if (!data || !data->parse_data(data)) + { + DESTROY_IF(data); + goto end; + } + this->data = chunk_clone(data->get_data(data)); + data->destroy(data); + break; + } + case PKCS7_SIGNED_CERT: + { + certificate_t *cert; + + DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); + cert = lib->creds->create(lib->creds, + CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, object, + BUILD_END); + if (cert) + { + this->certs->insert_last(this->certs, cert); + } + break; + } + case PKCS7_SIGNER_INFO: + signerInfos++; + DBG2(DBG_LIB, " signer #%d", signerInfos); + break; + case PKCS7_SIGNER_INFO_VERSION: + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + break; + case PKCS7_SIGNED_ISSUER: + { + identification_t *issuer; + + issuer = identification_create_from_encoding(ID_DER_ASN1_DN, object); + DBG2(DBG_LIB, " '%Y'", issuer); + issuer->destroy(issuer); + break; + } + case PKCS7_AUTH_ATTRIBUTES: + *object.ptr = ASN1_SET; + this->attributes = pkcs9_create_from_chunk(object, level+1); + *object.ptr = ASN1_CONTEXT_C_0; + break; + case PKCS7_DIGEST_ALGORITHM: + digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_DIGEST_ENC_ALGORITHM: + enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); + break; + case PKCS7_ENCRYPTED_DIGEST: + encrypted_digest = object; + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + return FALSE; + } + + /* check the signature only if a cacert is available */ + if (cacert != NULL) + { + signature_scheme_t scheme; + public_key_t *key; + + scheme = signature_scheme_from_oid(digest_alg); + if (scheme == SIGN_UNKNOWN) + { + DBG1(DBG_LIB, "unsupported signature scheme"); + return FALSE; + } + if (signerInfos == 0) + { + DBG1(DBG_LIB, "no signerInfo object found"); + return FALSE; + } + else if (signerInfos > 1) + { + DBG1(DBG_LIB, "more than one signerInfo object found"); + return FALSE; + } + if (this->attributes == NULL) + { + DBG1(DBG_LIB, "no authenticatedAttributes object found"); + return FALSE; + } + if (enc_alg != OID_RSA_ENCRYPTION) + { + DBG1(DBG_LIB, "only RSA digest encryption supported"); + return FALSE; + } + + /* verify the signature */ + key = cacert->get_public_key(cacert); + if (key == NULL) + { + DBG1(DBG_LIB, "no public key found in CA certificate"); + return FALSE; + } + if (key->verify(key, scheme, + this->attributes->get_encoding(this->attributes), encrypted_digest)) + { + DBG2(DBG_LIB, "signature is valid"); + } + else + { + DBG1(DBG_LIB, "invalid signature"); + key->destroy(key); + return FALSE; + } + key->destroy(key); + + if (this->data.ptr != NULL) + { + chunk_t messageDigest; + + messageDigest = this->attributes->get_attribute(this->attributes, + OID_PKCS9_MESSAGE_DIGEST); + if (messageDigest.ptr == NULL) + { + DBG1(DBG_LIB, "messageDigest attribute not found"); + return FALSE; + } + else + { + hash_algorithm_t algorithm; + hasher_t *hasher; + chunk_t hash; + bool valid; + + algorithm = hasher_algorithm_from_oid(digest_alg); + hasher = lib->crypto->create_hasher(lib->crypto, algorithm); + if (!hasher || !hasher->allocate_hash(hasher, this->data, &hash)) + { + DESTROY_IF(hasher); + DBG1(DBG_LIB, "hash algorithm %N not supported", + hash_algorithm_names, algorithm); + return FALSE; + } + hasher->destroy(hasher); + DBG3(DBG_LIB, "hash: %B", &hash); + + valid = chunk_equals(messageDigest, hash); + free(hash.ptr); + if (valid) + { + DBG2(DBG_LIB, "messageDigest is valid"); + } + else + { + DBG1(DBG_LIB, "invalid messageDigest"); + return FALSE; + } + } + } + } + return TRUE; +} + +/** + * ASN.1 definition of the PKCS#7 envelopedData type + */ +static const asn1Object_t envelopedDataObjects[] = { + { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ + { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */ + { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */ + { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */ + { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ + { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ + { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */ + { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */ + { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */ + { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ + { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ + { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */ + { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */ + { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } +}; +#define PKCS7_ENVELOPED_VERSION 1 +#define PKCS7_RECIPIENT_INFO_VERSION 4 +#define PKCS7_ISSUER 6 +#define PKCS7_SERIAL_NUMBER 7 +#define PKCS7_ENCRYPTION_ALG 8 +#define PKCS7_ENCRYPTED_KEY 9 +#define PKCS7_CONTENT_TYPE 12 +#define PKCS7_CONTENT_ENC_ALGORITHM 13 +#define PKCS7_ENCRYPTED_CONTENT 14 + +METHOD(pkcs7_t, parse_envelopedData, bool, + private_pkcs7_t *this, chunk_t serialNumber, private_key_t *key) +{ + asn1_parser_t *parser; + chunk_t object; + int objectID, version; + bool success = FALSE; + + chunk_t iv = chunk_empty; + chunk_t symmetric_key = chunk_empty; + chunk_t encrypted_content = chunk_empty; + + crypter_t *crypter = NULL; + + if (!parse_contentInfo(this) || + abort_parsing(this, OID_PKCS7_ENVELOPED_DATA)) + { + return FALSE; + } + + parser = asn1_parser_create(envelopedDataObjects, this->content); + parser->set_top_level(parser, this->level); + + while (parser->iterate(parser, &objectID, &object)) + { + u_int level = parser->get_level(parser); + + switch (objectID) + { + case PKCS7_ENVELOPED_VERSION: + { + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + if (version != 0) + { + DBG1(DBG_LIB, "envelopedData version is not 0"); + goto end; + } + break; + } + case PKCS7_RECIPIENT_INFO_VERSION: + { + version = object.len ? (int)*object.ptr : 0; + DBG2(DBG_LIB, " v%d", version); + if (version != 0) + { + DBG1(DBG_LIB, "recipient info version is not 0"); + goto end; + } + break; + } + case PKCS7_ISSUER: + { + identification_t *issuer; + + issuer = identification_create_from_encoding(ID_DER_ASN1_DN, + object); + DBG2(DBG_LIB, " '%Y'", issuer); + issuer->destroy(issuer); + break; + } + case PKCS7_SERIAL_NUMBER: + { + if (!chunk_equals(serialNumber, object)) + { + DBG1(DBG_LIB, "serial numbers do not match"); + goto end; + } + break; + } + case PKCS7_ENCRYPTION_ALG: + { + int alg; + + alg = asn1_parse_algorithmIdentifier(object, level, NULL); + if (alg != OID_RSA_ENCRYPTION) + { + DBG1(DBG_LIB, "only rsa encryption supported"); + goto end; + } + break; + } + case PKCS7_ENCRYPTED_KEY: + { + if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) + { + DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); + goto end; + } + DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); + break; + } + case PKCS7_CONTENT_TYPE: + { + if (asn1_known_oid(object) != OID_PKCS7_DATA) + { + DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); + goto end; + } + break; + } + case PKCS7_CONTENT_ENC_ALGORITHM: + { + encryption_algorithm_t enc_alg; + size_t key_size; + int alg; + + alg = asn1_parse_algorithmIdentifier(object, level, &iv); + enc_alg = encryption_algorithm_from_oid(alg, &key_size); + if (enc_alg == ENCR_UNDEFINED) + { + DBG1(DBG_LIB, "unsupported content encryption algorithm"); + goto end; + } + crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, + key_size); + if (crypter == NULL) + { + DBG1(DBG_LIB, "crypter %N not available", + encryption_algorithm_names, enc_alg); + goto end; + } + if (symmetric_key.len != crypter->get_key_size(crypter)) + { + DBG1(DBG_LIB, "symmetric key length %d is wrong", + symmetric_key.len); + goto end; + } + if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, + level + 1, "IV")) + { + DBG1(DBG_LIB, "IV could not be parsed"); + goto end; + } + if (iv.len != crypter->get_iv_size(crypter)) + { + DBG1(DBG_LIB, "IV length %d is wrong", iv.len); + goto end; + } + break; + } + case PKCS7_ENCRYPTED_CONTENT: + { + encrypted_content = object; + break; + } + } + } + success = parser->success(parser); + +end: + parser->destroy(parser); + if (!success) + { + goto failed; + } + success = FALSE; + + /* decrypt the content */ + if (!crypter->set_key(crypter, symmetric_key) || + !crypter->decrypt(crypter, encrypted_content, iv, &this->data)) + { + success = FALSE; + goto failed; + } + DBG4(DBG_LIB, "decrypted content with padding: %B", &this->data); + + /* remove the padding */ + { + u_char *pos = this->data.ptr + this->data.len - 1; + u_char pattern = *pos; + size_t padding = pattern; + + if (padding > this->data.len) + { + DBG1(DBG_LIB, "padding greater than data length"); + goto failed; + } + this->data.len -= padding; + + while (padding-- > 0) + { + if (*pos-- != pattern) + { + DBG1(DBG_LIB, "wrong padding pattern"); + goto failed; + } + } + } + success = TRUE; + +failed: + DESTROY_IF(crypter); + chunk_clear(&symmetric_key); + if (!success) + { + chunk_free(&this->data); + } + return success; +} + +METHOD(pkcs7_t, get_data, chunk_t, + private_pkcs7_t *this) +{ + return this->data; +} + +METHOD(pkcs7_t, get_contentInfo, chunk_t, + private_pkcs7_t *this) +{ + chunk_t content_type; + + /* create DER-encoded OID for pkcs7_contentInfo type */ + switch(this->type) + { + case OID_PKCS7_DATA: + case OID_PKCS7_SIGNED_DATA: + case OID_PKCS7_ENVELOPED_DATA: + case OID_PKCS7_SIGNED_ENVELOPED_DATA: + case OID_PKCS7_DIGESTED_DATA: + case OID_PKCS7_ENCRYPTED_DATA: + content_type = asn1_build_known_oid(this->type); + break; + case OID_UNKNOWN: + default: + DBG1(DBG_LIB, "invalid pkcs7 contentInfo type"); + return chunk_empty; + } + + return this->content.ptr == NULL + ? asn1_wrap(ASN1_SEQUENCE, "m", content_type) + : asn1_wrap(ASN1_SEQUENCE, "mm", content_type, + asn1_simple_object(ASN1_CONTEXT_C_0, this->content)); +} + +METHOD(pkcs7_t, create_certificate_enumerator, enumerator_t*, + private_pkcs7_t *this) +{ + return this->certs->create_enumerator(this->certs); +} + +METHOD(pkcs7_t, set_certificate, void, + private_pkcs7_t *this, certificate_t *cert) +{ + if (cert) + { + this->certs->insert_last(this->certs, cert); + } +} + +METHOD(pkcs7_t, set_attributes, void, + private_pkcs7_t *this, pkcs9_t *attributes) +{ + this->attributes = attributes; +} + +METHOD(pkcs7_t, get_attributes, pkcs9_t*, + private_pkcs7_t *this) +{ + return this->attributes; +} + +/** + * build a DER-encoded issuerAndSerialNumber object + */ +chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) +{ + identification_t *issuer = cert->get_issuer(cert); + chunk_t serial = chunk_empty; + + if (cert->get_type(cert) == CERT_X509) + { + x509_t *x509 = (x509_t*)cert; + serial = x509->get_serial(x509); + } + + return asn1_wrap(ASN1_SEQUENCE, "cm", + issuer->get_encoding(issuer), + asn1_integer("c", serial)); +} + +METHOD(pkcs7_t, build_envelopedData, bool, + private_pkcs7_t *this, certificate_t *cert, encryption_algorithm_t alg, + size_t key_size) +{ + chunk_t iv, symmetricKey, protectedKey, in, out; + crypter_t *crypter; + int alg_oid; + + /* select OID of symmetric encryption algorithm */ + alg_oid = encryption_algorithm_to_oid(alg, key_size); + if (alg_oid == OID_UNKNOWN) + { + DBG1(DBG_LIB, " encryption algorithm %N not supported", + encryption_algorithm_names, alg); + return FALSE; + } + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + if (crypter == NULL) + { + DBG1(DBG_LIB, " could not create crypter for algorithm %N", + encryption_algorithm_names, alg); + return FALSE; + } + + /* generate a true random symmetric encryption key + * and a pseudo-random iv + */ + { + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); + if (!rng || !rng->allocate_bytes(rng, crypter->get_key_size(crypter), + &symmetricKey)) + { + DBG1(DBG_LIB, " failed to allocate symmetric encryption key"); + DESTROY_IF(rng); + return FALSE; + } + DBG4(DBG_LIB, " symmetric encryption key: %B", &symmetricKey); + rng->destroy(rng); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng || !rng->allocate_bytes(rng, crypter->get_iv_size(crypter), + &iv)) + { + DBG1(DBG_LIB, " failed to allocate initialization vector"); + DESTROY_IF(rng); + return FALSE; + } + DBG4(DBG_LIB, " initialization vector: %B", &iv); + rng->destroy(rng); + } + + /* pad the data so that the total length becomes + * a multiple of the block size + */ + { + size_t block_size = crypter->get_block_size(crypter); + size_t padding = block_size - this->data.len % block_size; + + in.len = this->data.len + padding; + in.ptr = malloc(in.len); + + DBG2(DBG_LIB, " padding %d bytes of data to multiple block size of %d bytes", + (int)this->data.len, (int)in.len); + + /* copy data */ + memcpy(in.ptr, this->data.ptr, this->data.len); + /* append padding */ + memset(in.ptr + this->data.len, padding, padding); + } + DBG3(DBG_LIB, " padded unencrypted data: %B", &in); + + /* symmetric encryption of data object */ + if (!crypter->set_key(crypter, symmetricKey) || + !crypter->encrypt(crypter, in, iv, &out)) + { + crypter->destroy(crypter); + chunk_clear(&in); + chunk_clear(&symmetricKey); + chunk_free(&iv); + return FALSE; + } + crypter->destroy(crypter); + chunk_clear(&in); + DBG3(DBG_LIB, " encrypted data: %B", &out); + + /* protect symmetric key by public key encryption */ + { + public_key_t *key = cert->get_public_key(cert); + + if (key == NULL) + { + DBG1(DBG_LIB, " public key not found in encryption certificate"); + chunk_clear(&symmetricKey); + chunk_free(&iv); + chunk_free(&out); + return FALSE; + } + key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); + key->destroy(key); + chunk_clear(&symmetricKey); + } + + /* build pkcs7 enveloped data object */ + { + chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(alg_oid), + asn1_wrap(ASN1_OCTET_STRING, "m", iv)); + + chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm", + asn1_build_known_oid(OID_PKCS7_DATA), + contentEncryptionAlgorithm, + asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); + + chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m", protectedKey); + + chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm", + ASN1_INTEGER_0, + pkcs7_build_issuerAndSerialNumber(cert), + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + encryptedKey); + + this->content = asn1_wrap(ASN1_SEQUENCE, "cmm", + ASN1_INTEGER_0, + asn1_wrap(ASN1_SET, "m", recipientInfo), + encryptedContentInfo); + chunk_free(&this->data); + this->type = OID_PKCS7_ENVELOPED_DATA; + this->data = get_contentInfo(this); + } + return TRUE; +} + +METHOD(pkcs7_t, build_signedData, bool, + private_pkcs7_t *this, private_key_t *private_key, hash_algorithm_t alg) +{ + chunk_t authenticatedAttributes = chunk_empty; + chunk_t encryptedDigest = chunk_empty; + chunk_t signerInfo, encoding = chunk_empty; + signature_scheme_t scheme; + int digest_oid; + certificate_t *cert; + + if (this->certs->get_first(this->certs, (void**)&cert) != SUCCESS) + { + DBG1(DBG_LIB, " no pkcs7 signer certificate found"); + return FALSE; + } + digest_oid = hasher_algorithm_to_oid(alg); + scheme = signature_scheme_from_oid(digest_oid); + + if (this->attributes != NULL) + { + if (this->data.ptr != NULL) + { + chunk_t messageDigest, signingTime, attributes; + hasher_t *hasher; + time_t now; + + hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (!hasher || + !hasher->allocate_hash(hasher, this->data, &messageDigest)) + { + DESTROY_IF(hasher); + DBG1(DBG_LIB, " hash algorithm %N not support", + hash_algorithm_names, alg); + return FALSE; + } + hasher->destroy(hasher); + this->attributes->set_attribute(this->attributes, + OID_PKCS9_MESSAGE_DIGEST, + messageDigest); + free(messageDigest.ptr); + + /* take the current time as signingTime */ + now = time(NULL); + signingTime = asn1_from_time(&now, ASN1_UTCTIME); + this->attributes->set_attribute_raw(this->attributes, + OID_PKCS9_SIGNING_TIME, signingTime); + this->attributes->set_attribute_raw(this->attributes, + OID_PKCS9_CONTENT_TYPE, + asn1_build_known_oid(OID_PKCS7_DATA)); + + attributes = this->attributes->get_encoding(this->attributes); + + private_key->sign(private_key, scheme, attributes, &encryptedDigest); + authenticatedAttributes = chunk_clone(attributes); + *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; + } + } + else if (this->data.ptr != NULL) + { + private_key->sign(private_key, scheme, this->data, &encryptedDigest); + } + if (encryptedDigest.ptr) + { + encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", encryptedDigest); + } + signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm", + ASN1_INTEGER_1, + pkcs7_build_issuerAndSerialNumber(cert), + asn1_algorithmIdentifier(digest_oid), + authenticatedAttributes, + asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), + encryptedDigest); + + if (this->data.ptr != NULL) + { + chunk_free(&this->content); + this->content = asn1_simple_object(ASN1_OCTET_STRING, this->data); + chunk_free(&this->data); + } + this->type = OID_PKCS7_DATA; + this->data = get_contentInfo(this); + chunk_free(&this->content); + + cert->get_encoding(cert, CERT_ASN1_DER, &encoding); + + this->content = asn1_wrap(ASN1_SEQUENCE, "cmcmm", + ASN1_INTEGER_1, + asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_oid)), + this->data, + asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding), + asn1_wrap(ASN1_SET, "m", signerInfo)); + chunk_free(&this->data); + this->type = OID_PKCS7_SIGNED_DATA; + this->data = get_contentInfo(this); + + return TRUE; +} + +METHOD(pkcs7_t, destroy, void, + private_pkcs7_t *this) +{ + DESTROY_IF(this->attributes); + this->certs->destroy_offset(this->certs, offsetof(certificate_t, destroy)); + free(this->content.ptr); + free(this->data.ptr); + free(this); +} + +/** + * Generic private constructor + */ +static private_pkcs7_t *pkcs7_create_empty(void) +{ + private_pkcs7_t *this; + + INIT(this, + .public = { + .is_data = _is_data, + .is_signedData = _is_signedData, + .is_envelopedData = _is_envelopedData, + .parse_data = _parse_data, + .parse_signedData = _parse_signedData, + .parse_envelopedData = _parse_envelopedData, + .get_data = _get_data, + .get_contentInfo = _get_contentInfo, + .create_certificate_enumerator = _create_certificate_enumerator, + .set_certificate = _set_certificate, + .set_attributes = _set_attributes, + .get_attributes = _get_attributes, + .build_envelopedData = _build_envelopedData, + .build_signedData = _build_signedData, + .destroy = _destroy, + }, + .type = OID_UNKNOWN, + .certs = linked_list_create(), + ); + + return this; +} + +/* + * Described in header. + */ +pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level) +{ + private_pkcs7_t *this = pkcs7_create_empty(); + + this->level = level; + this->data = chunk_clone(chunk); + + return &this->public; +} + +/* + * Described in header. + */ +pkcs7_t *pkcs7_create_from_data(chunk_t data) +{ + private_pkcs7_t *this = pkcs7_create_empty(); + + this->data = chunk_clone(data); + + return &this->public; +} + diff --git a/src/libstrongswan/crypto/pkcs7.h b/src/libstrongswan/crypto/pkcs7.h new file mode 100644 index 000000000..7c9a6b037 --- /dev/null +++ b/src/libstrongswan/crypto/pkcs7.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Copyright (C) 2002-2008 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pkcs7 pkcs7 + * @{ @ingroup crypto + */ + +#ifndef PKCS7_H_ +#define PKCS7_H_ + +typedef struct pkcs7_t pkcs7_t; + +#include +#include +#include +#include +#include + +/** + * PKCS#7 contentInfo object. + */ +struct pkcs7_t { + + /** + * Check if the PKCS#7 contentType is data + * + * @return TRUE if the contentType is data + */ + bool (*is_data) (pkcs7_t *this); + + /** + * Check if the PKCS#7 contentType is signedData + * + * @return TRUE if the contentType is signedData + */ + bool (*is_signedData) (pkcs7_t *this); + + /** + * Check if the PKCS#7 contentType is envelopedData + * + * @return TRUE if the contentType is envelopedData + */ + bool (*is_envelopedData) (pkcs7_t *this); + + /** + * Parse a PKCS#7 data content. + * + * @return TRUE if parsing was successful + */ + bool (*parse_data) (pkcs7_t *this); + + /** + * Parse a PKCS#7 signedData content. The contained PKCS#7 data is parsed + * and verified. + * + * @param cacert cacert used to verify the signature + * @return TRUE if parsing was successful + */ + bool (*parse_signedData) (pkcs7_t *this, certificate_t *cacert); + + /** + * Parse a PKCS#7 envelopedData content. + * + * @param serialNumber serialNumber of the request + * @param key private key used to decrypt the symmetric key + * @return TRUE if parsing was successful + */ + bool (*parse_envelopedData) (pkcs7_t *this, chunk_t serialNumber, + private_key_t *key); + + /** + * Returns the parsed data object + * + * @return chunk containing the data object + */ + chunk_t (*get_data) (pkcs7_t *this); + + /** + * Returns the a DER-encoded contentInfo object + * + * @return chunk containing the contentInfo object + */ + chunk_t (*get_contentInfo) (pkcs7_t *this); + + /** + * Create an enumerator for the certificates. + * + * @return enumerator for the certificates + */ + enumerator_t *(*create_certificate_enumerator) (pkcs7_t *this); + + /** + * Add a certificate. + * + * @param cert certificate to be included (gets adopted) + */ + void (*set_certificate) (pkcs7_t *this, certificate_t *cert); + + /** + * Add authenticated attributes. + * + * @param attributes attributes to be included (gets adopted) + */ + void (*set_attributes) (pkcs7_t *this, pkcs9_t *attributes); + + /** + * Get attributes. + * + * @return attributes (internal data) + */ + pkcs9_t *(*get_attributes) (pkcs7_t *this); + + /** + * Build a data object + * + * @return TRUE if build was successful + */ + bool (*build_data) (pkcs7_t *this); + + /** + * Build an envelopedData object + * + * @param cert receivers's certificate + * @param alg encryption algorithm + * @param key_size key size to use + * @return TRUE if build was successful + */ + bool (*build_envelopedData) (pkcs7_t *this, certificate_t *cert, + encryption_algorithm_t alg, size_t key_size); + + /** + * Build an signedData object + * + * @param key signer's private key + * @param alg digest algorithm used for signature + * @return TRUE if build was successful + */ + bool (*build_signedData) (pkcs7_t *this, private_key_t *key, + hash_algorithm_t alg); + + /** + * Destroys the contentInfo object. + */ + void (*destroy) (pkcs7_t *this); +}; + +/** + * Read a PKCS#7 contentInfo object from a DER encoded chunk. + * + * @param chunk chunk containing DER encoded data + * @param level ASN.1 parsing start level + * @return created pkcs7_contentInfo object, or NULL if invalid. + */ +pkcs7_t *pkcs7_create_from_chunk(chunk_t chunk, u_int level); + +/** + * Create a PKCS#7 contentInfo object + * + * @param data chunk containing data + * @return created pkcs7_contentInfo object. + */ +pkcs7_t *pkcs7_create_from_data(chunk_t data); + +#endif /** PKCS7_H_ @}*/ diff --git a/src/libstrongswan/crypto/pkcs9.c b/src/libstrongswan/crypto/pkcs9.c index 63a615238..d24ab1b80 100644 --- a/src/libstrongswan/crypto/pkcs9.c +++ b/src/libstrongswan/crypto/pkcs9.c @@ -1,5 +1,6 @@ /* - * Copyright (C)2008 Andreas Steffen + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * * This program is free software; you can redistribute it and/or modify it @@ -73,58 +74,6 @@ struct attribute_t { }; -/** - * PKCS#9 attribute type OIDs - */ -static chunk_t ASN1_contentType_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03 -); -static chunk_t ASN1_messageDigest_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x04 -); -static chunk_t ASN1_signingTime_oid = chunk_from_chars( - 0x06, 0x09, - 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x05 -); -static chunk_t ASN1_messageType_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x02 -); -static chunk_t ASN1_senderNonce_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x05 -); -static chunk_t ASN1_transId_oid = chunk_from_chars( - 0x06, 0x0A, - 0x60, 0x86, 0x48, 0x01, 0x86, 0xF8, 0x45, 0x01, 0x09, 0x07 -); - -/** - * return the ASN.1 encoded OID of a PKCS#9 attribute - */ -static chunk_t asn1_attributeIdentifier(int oid) -{ - switch (oid) - { - case OID_PKCS9_CONTENT_TYPE: - return ASN1_contentType_oid; - case OID_PKCS9_MESSAGE_DIGEST: - return ASN1_messageDigest_oid; - case OID_PKCS9_SIGNING_TIME: - return ASN1_signingTime_oid; - case OID_PKI_MESSAGE_TYPE: - return ASN1_messageType_oid; - case OID_PKI_SENDER_NONCE: - return ASN1_senderNonce_oid; - case OID_PKI_TRANS_ID: - return ASN1_transId_oid;; - default: - return chunk_empty; - } -} - /** * return the ASN.1 encoding of a PKCS#9 attribute */ @@ -188,8 +137,8 @@ static attribute_t *attribute_create(int oid, chunk_t value) .destroy = attribute_destroy, .oid = oid, .value = chunk_clone(value), - .encoding = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_attributeIdentifier(oid), + .encoding = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_build_known_oid(oid), asn1_simple_object(ASN1_SET, value)), ); @@ -263,43 +212,30 @@ METHOD(pkcs9_t, get_attribute, chunk_t, } } enumerator->destroy(enumerator); + if (value.ptr && + !asn1_parse_simple_object(&value, asn1_attributeType(oid), 0, + oid_names[oid].name)) + { + return chunk_empty; + } return value; } -METHOD(pkcs9_t, set_attribute, void, +METHOD(pkcs9_t, set_attribute_raw, void, private_pkcs9_t *this, int oid, chunk_t value) { attribute_t *attribute = attribute_create(oid, value); - this->attributes->insert_last(this->attributes, (void*)attribute); -} - -METHOD(pkcs9_t, get_messageDigest, chunk_t, - private_pkcs9_t *this) -{ - const int oid = OID_PKCS9_MESSAGE_DIGEST; - chunk_t value = get_attribute(this, oid); - - if (value.ptr == NULL) - { - return chunk_empty; - } - if (!asn1_parse_simple_object(&value, asn1_attributeType(oid), 0, - oid_names[oid].name)) - { - return chunk_empty; - } - return chunk_clone(value); + this->attributes->insert_last(this->attributes, attribute); + chunk_free(&value); } -METHOD(pkcs9_t, set_messageDigest, void, - private_pkcs9_t *this, chunk_t value) +METHOD(pkcs9_t, set_attribute, void, + private_pkcs9_t *this, int oid, chunk_t value) { - const int oid = OID_PKCS9_MESSAGE_DIGEST; - chunk_t messageDigest = asn1_simple_object(asn1_attributeType(oid), value); + chunk_t attr = asn1_simple_object(asn1_attributeType(oid), value); - set_attribute(this, oid, messageDigest); - free(messageDigest.ptr); + set_attribute_raw(this, oid, attr); } METHOD(pkcs9_t, destroy, void, @@ -323,8 +259,7 @@ static private_pkcs9_t *pkcs9_create_empty(void) .get_encoding = _get_encoding, .get_attribute = _get_attribute, .set_attribute = _set_attribute, - .get_messageDigest = _get_messageDigest, - .set_messageDigest = _set_messageDigest, + .set_attribute_raw = _set_attribute_raw, .destroy = _destroy, }, .attributes = linked_list_create(), diff --git a/src/libstrongswan/crypto/pkcs9.h b/src/libstrongswan/crypto/pkcs9.h index 5b85692d6..c442d4441 100644 --- a/src/libstrongswan/crypto/pkcs9.h +++ b/src/libstrongswan/crypto/pkcs9.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Andreas Steffen * Hochschule fuer Technik Rapperswil, Switzerland * @@ -46,7 +47,7 @@ struct pkcs9_t { * Gets a PKCS#9 attribute * * @param oid OID of the attribute - * @return ASN.1 encoded value of the attribute + * @return value of the attribute (internal data) */ chunk_t (*get_attribute) (pkcs9_t *this, int oid); @@ -54,23 +55,17 @@ struct pkcs9_t { * Adds a PKCS#9 attribute * * @param oid OID of the attribute - * @param value ASN.1 encoded value of the attribute + * @param value value of the attribute (gets cloned) */ void (*set_attribute) (pkcs9_t *this, int oid, chunk_t value); /** - * Gets a PKCS#9 messageDigest attribute + * Adds a ASN.1 encoded PKCS#9 attribute * - * @return messageDigest - */ - chunk_t (*get_messageDigest) (pkcs9_t *this); - - /** - * Add a PKCS#9 messageDigest attribute - * - * @param value messageDigest + * @param oid OID of the attribute + * @param value ASN.1 encoded value of the attribute (gets adopted) */ - void (*set_messageDigest) (pkcs9_t *this, chunk_t value); + void (*set_attribute_raw) (pkcs9_t *this, int oid, chunk_t value); /** * Destroys the PKCS#9 attribute list. diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index 8e815e608..94be1d5bf 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -25,6 +25,7 @@ typedef struct private_prf_plus_t private_prf_plus_t; * */ struct private_prf_plus_t { + /** * Public interface of prf_plus_t. */ @@ -41,65 +42,74 @@ struct private_prf_plus_t { chunk_t seed; /** - * Buffer to store current PRF result. + * Octet which will be appended to the seed, 0 if not used */ - chunk_t buffer; + u_int8_t counter; /** * Already given out bytes in current buffer. */ - size_t given_out; + size_t used; /** - * Octet which will be appended to the seed. + * Buffer to store current PRF result. */ - u_int8_t appending_octet; + chunk_t buffer; }; -METHOD(prf_plus_t, get_bytes, void, +METHOD(prf_plus_t, get_bytes, bool, private_prf_plus_t *this, size_t length, u_int8_t *buffer) { - chunk_t appending_chunk; - size_t bytes_in_round; - size_t total_bytes_written = 0; - - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; + size_t round, written = 0; while (length > 0) - { /* still more to do... */ - if (this->buffer.len == this->given_out) - { /* no bytes left in buffer, get next*/ - this->prf->get_bytes(this->prf, this->buffer, NULL); - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; + { + if (this->buffer.len == this->used) + { /* buffer used, get next round */ + if (!this->prf->get_bytes(this->prf, this->buffer, NULL)) + { + return FALSE; + } + if (this->counter) + { + if (!this->prf->get_bytes(this->prf, this->seed, NULL) || + !this->prf->get_bytes(this->prf, + chunk_from_thing(this->counter), this->buffer.ptr)) + { + return FALSE; + } + this->counter++; + } + else + { + if (!this->prf->get_bytes(this->prf, this->seed, + this->buffer.ptr)) + { + return FALSE; + } + } + this->used = 0; } - /* how many bytes can we write in this round ? */ - bytes_in_round = min(length, this->buffer.len - this->given_out); - /* copy bytes from buffer with offset */ - memcpy(buffer + total_bytes_written, this->buffer.ptr + this->given_out, bytes_in_round); - - length -= bytes_in_round; - this->given_out += bytes_in_round; - total_bytes_written += bytes_in_round; + round = min(length, this->buffer.len - this->used); + memcpy(buffer + written, this->buffer.ptr + this->used, round); + + length -= round; + this->used += round; + written += round; } + return TRUE; } -METHOD(prf_plus_t, allocate_bytes, void, +METHOD(prf_plus_t, allocate_bytes, bool, private_prf_plus_t *this, size_t length, chunk_t *chunk) { if (length) { - chunk->ptr = malloc(length); - chunk->len = length; - get_bytes(this, length, chunk->ptr); - } - else - { - *chunk = chunk_empty; + *chunk = chunk_alloc(length); + return get_bytes(this, length, chunk->ptr); } + *chunk = chunk_empty; + return TRUE; } METHOD(prf_plus_t, destroy, void, @@ -113,10 +123,9 @@ METHOD(prf_plus_t, destroy, void, /* * Description in header. */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed) { private_prf_plus_t *this; - chunk_t appending_chunk; INIT(this, .public = { @@ -125,25 +134,30 @@ prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) .destroy = _destroy, }, .prf = prf, + .seed = chunk_clone(seed), + .buffer = chunk_alloc(prf->get_block_size(prf)), ); - /* allocate buffer for prf output */ - this->buffer.len = prf->get_block_size(prf); - this->buffer.ptr = malloc(this->buffer.len); - - this->appending_octet = 0x01; - - /* clone seed */ - this->seed.ptr = clalloc(seed.ptr, seed.len); - this->seed.len = seed.len; - - /* do the first run */ - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; + if (counter) + { + this->counter = 0x01; + if (!this->prf->get_bytes(this->prf, this->seed, NULL) || + !this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), + this->buffer.ptr)) + { + destroy(this); + return NULL; + } + this->counter++; + } + else + { + if (!this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr)) + { + destroy(this); + return NULL; + } + } - return &(this->public); + return &this->public; } diff --git a/src/libstrongswan/crypto/prf_plus.h b/src/libstrongswan/crypto/prf_plus.h index 4179f2695..f994dce16 100644 --- a/src/libstrongswan/crypto/prf_plus.h +++ b/src/libstrongswan/crypto/prf_plus.h @@ -27,52 +27,44 @@ typedef struct prf_plus_t prf_plus_t; #include /** - * Implementation of the prf+ function described in IKEv2 RFC. - * - * This class implements the prf+ algorithm. Internally it uses a pseudo random - * function, which implements the prf_t interface. - * See IKEv2 RFC 2.13. + * Implementation of the prf+ function used in IKEv1/IKEv2 keymat extension. */ struct prf_plus_t { + /** * Get pseudo random bytes. * - * Get the next few bytes of the prf+ output. Space - * must be allocated by the caller. - * * @param length number of bytes to get * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes generated successfully */ - void (*get_bytes) (prf_plus_t *this, size_t length, u_int8_t *buffer); + bool (*get_bytes)(prf_plus_t *this, size_t length, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Allocate pseudo random bytes. * - * Get the next few bytes of the prf+ output. This function - * will allocate the required space. - * * @param length number of bytes to get * @param chunk chunk which will hold generated bytes + * @return TRUE if bytes allocated successfully */ - void (*allocate_bytes) (prf_plus_t *this, size_t length, chunk_t *chunk); + bool (*allocate_bytes)(prf_plus_t *this, size_t length, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Destroys a prf_plus_t object. */ - void (*destroy) (prf_plus_t *this); + void (*destroy)(prf_plus_t *this); }; /** * Creates a new prf_plus_t object. * - * Seed will be cloned. prf will - * not be cloned, must be destroyed outside after - * prf_plus_t usage. - * - * @param prf prf object to use + * @param prf prf object to use, must be destroyd after prf+. + * @param counter use an appending counter byte (for IKEv2 variant) * @param seed input seed for prf - * @return prf_plus_t object + * @return prf_plus_t object, NULL on failure */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed); +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed); #endif /** PRF_PLUS_H_ @}*/ diff --git a/src/libstrongswan/crypto/prfs/mac_prf.c b/src/libstrongswan/crypto/prfs/mac_prf.c new file mode 100644 index 000000000..b5f6be982 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/mac_prf.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "mac_prf.h" + +typedef struct private_prf_t private_prf_t; + +/** + * Private data of a mac_prf_t object. + */ +struct private_prf_t { + + /** + * Public interface + */ + prf_t public; + + /** + * MAC to use + */ + mac_t *mac; +}; + +METHOD(prf_t, get_bytes, bool, + private_prf_t *this, chunk_t seed, u_int8_t *buffer) +{ + return this->mac->get_mac(this->mac, seed, buffer); +} + +METHOD(prf_t, allocate_bytes, bool, + private_prf_t *this, chunk_t seed, chunk_t *chunk) +{ + if (chunk) + { + *chunk = chunk_alloc(this->mac->get_mac_size(this->mac)); + return this->mac->get_mac(this->mac, seed, chunk->ptr); + } + return this->mac->get_mac(this->mac, seed, NULL); +} + +METHOD(prf_t, get_block_size, size_t, + private_prf_t *this) +{ + return this->mac->get_mac_size(this->mac); +} + +METHOD(prf_t, get_key_size, size_t, + private_prf_t *this) +{ + /* IKEv2 uses MAC size as key size */ + return this->mac->get_mac_size(this->mac); +} + +METHOD(prf_t, set_key, bool, + private_prf_t *this, chunk_t key) +{ + return this->mac->set_key(this->mac, key); +} + +METHOD(prf_t, destroy, void, + private_prf_t *this) +{ + this->mac->destroy(this->mac); + free(this); +} + +/* + * Described in header. + */ +prf_t *mac_prf_create(mac_t *mac) +{ + private_prf_t *this; + + INIT(this, + .public = { + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .get_block_size = _get_block_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _destroy, + }, + .mac = mac, + ); + + return &this->public; +} diff --git a/src/libstrongswan/crypto/prfs/mac_prf.h b/src/libstrongswan/crypto/prfs/mac_prf.h new file mode 100644 index 000000000..b2c0c6e17 --- /dev/null +++ b/src/libstrongswan/crypto/prfs/mac_prf.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mac_prf mac_prf + * @{ @ingroup crypto + */ + +#ifndef MAC_PRF_H_ +#define MAC_PRF_H_ + +#include +#include + +/** + * Creates an implementation of the prf_t interface using the provided mac_t + * implementation. Basically a simple wrapper to map the interface. + * + * @param mac mac_t implementation + * @return prf_t object + */ +prf_t *mac_prf_create(mac_t *mac); + +#endif /** MAC_PRF_H_ @}*/ diff --git a/src/libstrongswan/crypto/prfs/prf.h b/src/libstrongswan/crypto/prfs/prf.h index ad15205d3..46e23b244 100644 --- a/src/libstrongswan/crypto/prfs/prf.h +++ b/src/libstrongswan/crypto/prfs/prf.h @@ -71,28 +71,33 @@ extern enum_name_t *pseudo_random_function_names; * Generic interface for pseudo-random-functions. */ struct prf_t { + /** * Generates pseudo random bytes and writes them in the buffer. * * @param seed a chunk containing the seed for the next bytes * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes generated successfully */ - void (*get_bytes) (prf_t *this, chunk_t seed, u_int8_t *buffer); + bool (*get_bytes)(prf_t *this, chunk_t seed, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generates pseudo random bytes and allocate space for them. * * @param seed a chunk containing the seed for the next bytes * @param chunk chunk which will hold generated bytes + * @return TRUE if bytes allocated and generated successfully */ - void (*allocate_bytes) (prf_t *this, chunk_t seed, chunk_t *chunk); + bool (*allocate_bytes)(prf_t *this, chunk_t seed, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Get the block size of this prf_t object. * * @return block size in bytes */ - size_t (*get_block_size) (prf_t *this); + size_t (*get_block_size)(prf_t *this); /** * Get the key size of this prf_t object. @@ -102,19 +107,21 @@ struct prf_t { * * @return key size in bytes */ - size_t (*get_key_size) (prf_t *this); + size_t (*get_key_size)(prf_t *this); /** * Set the key for this prf_t object. * * @param key key to set + * @return TRUE if key set successfully */ - void (*set_key) (prf_t *this, chunk_t key); + bool (*set_key)(prf_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a prf object. */ - void (*destroy) (prf_t *this); + void (*destroy)(prf_t *this); }; #endif /** PRF_H_ @}*/ diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.c b/src/libstrongswan/crypto/proposal/proposal_keywords.c index 2060864a5..7356dc367 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.c +++ b/src/libstrongswan/crypto/proposal/proposal_keywords.c @@ -1,38 +1,6 @@ -/* C code produced by gperf version 3.0.3 */ -/* Command-line: /usr/bin/gperf -N proposal_get_token -m 10 -C -G -c -t -D */ -/* Computed positions: -k'1,5,7,10,15,$' */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - - -/* proposal keywords - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -45,280 +13,134 @@ error "gperf generated tables don't work with this execution character set. Plea * for more details. */ -#include +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "proposal_keywords.h" +#include "proposal_keywords_static.h" -#include -#include -#include -#include +#include +#include -struct proposal_token { - char *name; - transform_type_t type; - u_int16_t algorithm; - u_int16_t keysize; -}; +typedef struct private_proposal_keywords_t private_proposal_keywords_t; + +struct private_proposal_keywords_t { + + /** + * public interface + */ + proposal_keywords_t public; + + /** + * registered tokens, as proposal_token_t + */ + linked_list_t * tokens; -#define TOTAL_KEYWORDS 122 -#define MIN_WORD_LENGTH 3 -#define MAX_WORD_LENGTH 17 -#define MIN_HASH_VALUE 9 -#define MAX_HASH_VALUE 213 -/* maximum key range = 205, duplicates = 0 */ + /** + * rwlock to lock access to modules + */ + rwlock_t *lock; +}; -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -hash (str, len) - register const char *str; - register unsigned int len; +/** + * Find the token object for the algorithm specified. + */ +static const proposal_token_t* find_token(private_proposal_keywords_t *this, + const char *str) { - static const unsigned char asso_values[] = - { - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 14, 9, - 4, 34, 66, 19, 8, 4, 5, 3, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 131, 214, 3, 22, 21, - 3, 1, 101, 48, 3, 4, 214, 214, 3, 10, - 57, 4, 214, 214, 94, 6, 3, 32, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, - 214, 214, 214, 214, 214, 214, 214 - }; - register int hval = len; + proposal_token_t *token, *found = NULL; + enumerator_t *enumerator; + + this->lock->read_lock(this->lock); + enumerator = this->tokens->create_enumerator(this->tokens); + while (enumerator->enumerate(enumerator, &token)) + { + if (streq(token->name, str)) + { + found = token; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + return found; +} - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[14]]; - /*FALLTHROUGH*/ - case 14: - case 13: - case 12: - case 11: - case 10: - hval += asso_values[(unsigned char)str[9]]; - /*FALLTHROUGH*/ - case 9: - case 8: - case 7: - hval += asso_values[(unsigned char)str[6]]; - /*FALLTHROUGH*/ - case 6: - case 5: - hval += asso_values[(unsigned char)str[4]]; - /*FALLTHROUGH*/ - case 4: - case 3: - case 2: - case 1: - hval += asso_values[(unsigned char)str[0]+1]; - break; - } - return hval + asso_values[(unsigned char)str[len - 1]]; +METHOD(proposal_keywords_t, get_token, const proposal_token_t*, + private_proposal_keywords_t *this, const char *str) +{ + const proposal_token_t *token = proposal_get_token_static(str, strlen(str)); + return token ?: find_token(this, str); } -static const struct proposal_token wordlist[] = - { - {"sha", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, - {"des", ENCRYPTION_ALGORITHM, ENCR_DES, 0}, - {"null", ENCRYPTION_ALGORITHM, ENCR_NULL, 0}, - {"sha1", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, - {"serpent", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, - {"camellia", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, - {"sha512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, - {"serpent192", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192}, - {"serpent128", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, - {"camellia192", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192}, - {"cast128", ENCRYPTION_ALGORITHM, ENCR_CAST, 128}, - {"camellia128", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, - {"aes", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, - {"serpent256", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256}, - {"aes192", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192}, - {"sha256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, - {"aes128", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, - {"camellia192ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, - {"camellia128ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, - {"camellia192ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, - {"camellia128ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, - {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, - {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, - {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, - {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, - {"camellia192ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, - {"camellia128ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, - {"camellia256", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256}, - {"twofish", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, - {"camellia256ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, - {"aes256", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256}, - {"camellia256ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, - {"twofish192", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192}, - {"camellia256ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, - {"twofish128", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, - {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, - {"camellia256ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, - {"camelliaxcbc", INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0}, - {"twofish256", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256}, - {"aes192ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, - {"aes128ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, - {"aes192ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, - {"aes128ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, - {"aes192ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, - {"aes128ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, - {"aes192ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, - {"aes128ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, - {"aes192ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, - {"aes128ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, - {"3des", ENCRYPTION_ALGORITHM, ENCR_3DES, 0}, - {"modp8192", DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0}, - {"modp768", DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0}, - {"md5", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0}, - {"sha384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0}, - {"aescmac", INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0}, - {"aes256ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, - {"md5_128", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0}, - {"aes256ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, - {"aes256ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, - {"aes256ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, - {"aes256ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, - {"aesxcbc", INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0}, - {"aes192gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, - {"aes128gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, - {"aes192gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, - {"aes128gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, - {"aes192gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, - {"aes128gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, - {"aes192gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, - {"aes128gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, - {"aes192gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, - {"aes128gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, - {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, - {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, - {"modp1024s160", DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0}, - {"modp3072", DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0}, - {"aes256gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, - {"aes256gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, - {"aes256gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, - {"ecp192", DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0}, - {"aes256gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, - {"modp1536", DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0}, - {"aes256gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, - {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, - {"ecp521", DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0}, - {"camellia192ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192}, - {"camellia128ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128}, - {"noesn", EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0}, - {"aes192gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192}, - {"aes128gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128}, - {"modpnull", DIFFIE_HELLMAN_GROUP, MODP_NULL, 0}, - {"aes192ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, - {"aes128ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, - {"ecp256", DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0}, - {"camellia256ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256}, - {"blowfish", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, - {"modp2048", DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0}, - {"aes256gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256}, - {"modp4096", DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0}, - {"modp1024", DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0}, - {"blowfish192", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192}, - {"aes256ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, - {"blowfish128", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, - {"aes192ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192}, - {"aes128ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128}, - {"modp2048s256", DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0}, - {"sha2_512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, - {"aes192gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, - {"aes128gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, - {"esn", EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0}, - {"sha1_160", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0}, - {"aes256ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256}, - {"blowfish256", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256}, - {"sha2_256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, - {"sha256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, - {"aes256gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, - {"sha2_256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, - {"ecp224", DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0}, - {"ecp384", DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0}, - {"modp6144", DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0}, - {"modp2048s224", DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0}, - {"sha2_384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0} - }; +METHOD(proposal_keywords_t, register_token, void, + private_proposal_keywords_t *this, const char *name, transform_type_t type, + u_int16_t algorithm, u_int16_t keysize) +{ + proposal_token_t *token; + + INIT(token, + .name = strdup(name), + .type = type, + .algorithm = algorithm, + .keysize = keysize, + ); -static const short lookup[] = - { - -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, - 1, 2, -1, -1, -1, -1, 3, 4, -1, -1, - -1, 5, 6, -1, -1, 7, -1, 8, 9, 10, - 11, 12, -1, 13, -1, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, - 35, -1, 36, -1, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, -1, 58, -1, 59, -1, - 60, -1, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, -1, 75, -1, 76, - -1, 77, -1, 78, 79, 80, 81, 82, -1, 83, - 84, 85, 86, 87, -1, 88, 89, -1, 90, -1, - -1, 91, 92, -1, 93, -1, -1, 94, -1, 95, - 96, 97, 98, -1, 99, -1, 100, 101, 102, 103, - 104, 105, -1, -1, -1, 106, -1, -1, 107, 108, - -1, 109, -1, -1, 110, 111, 112, -1, -1, 113, - 114, -1, -1, -1, 115, 116, -1, 117, 118, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 119, -1, -1, -1, 120, - -1, -1, -1, 121 - }; + this->lock->write_lock(this->lock); + this->tokens->insert_first(this->tokens, token); + this->lock->unlock(this->lock); +} -#ifdef __GNUC__ -__inline -#ifdef __GNUC_STDC_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const struct proposal_token * -proposal_get_token (str, len) - register const char *str; - register unsigned int len; +METHOD(proposal_keywords_t, destroy, void, + private_proposal_keywords_t *this) { - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = hash (str, len); + proposal_token_t *token; + + while (this->tokens->remove_first(this->tokens, (void**)&token) == SUCCESS) + { + free(token->name); + free(token); + } + this->tokens->destroy(this->tokens); + this->lock->destroy(this->lock); + free(this); +} - if (key <= MAX_HASH_VALUE && key >= 0) - { - register int index = lookup[key]; +/* + * Described in header. + */ +proposal_keywords_t *proposal_keywords_create() +{ + private_proposal_keywords_t *this; - if (index >= 0) - { - register const char *s = wordlist[index].name; + INIT(this, + .public = { + .get_token = _get_token, + .register_token = _register_token, + .destroy = _destroy, + }, + .tokens = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') - return &wordlist[index]; - } - } - } - return 0; + return &this->public; } diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.h b/src/libstrongswan/crypto/proposal/proposal_keywords.h index 53fa1728f..d6107abc0 100644 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.h +++ b/src/libstrongswan/crypto/proposal/proposal_keywords.h @@ -1,6 +1,6 @@ -/* proposal keywords - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -13,22 +13,103 @@ * for more details. */ -#ifndef _PROPOSAL_KEYWORDS_H_ -#define _PROPOSAL_KEYWORDS_H_ +/* + * Copyright (c) 2012 Nanoteq Pty Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * @defgroup proposal_keywords proposal_keywords + * @{ @ingroup crypto + */ + +#ifndef PROPOSAL_KEYWORDS_H_ +#define PROPOSAL_KEYWORDS_H_ + +typedef struct proposal_token_t proposal_token_t; +typedef struct proposal_keywords_t proposal_keywords_t; + +#include #include -typedef struct proposal_token proposal_token_t; +/** + * Class representing a proposal token. + */ +struct proposal_token_t { + + /** + * The name of the token. + */ + char *name; + + /** + * The type of transform in the token. + */ + transform_type_t type; + + /** + * The IKE id of the algorithm. + */ + u_int16_t algorithm; -struct proposal_token { - char *name; - transform_type_t type; - u_int16_t algorithm; - u_int16_t keysize; + /** + * The key size associated with the specific algorithm. + */ + u_int16_t keysize; }; -extern const proposal_token_t* proposal_get_token(register const char *str, - register unsigned int len); +/** + * Class to manage proposal keywords + */ +struct proposal_keywords_t { + + /** + * Returns the proposal token for the specified string if a token exists. + * + * @param str the string containing the name of the token + * @return proposal_token if found, NULL otherwise + */ + const proposal_token_t *(*get_token)(proposal_keywords_t *this, + const char *str); -#endif /* _PROPOSAL_KEYWORDS_H_ */ + /** + * Register a new proposal token for an algorithm. + * + * @param name the string containing the name of the token + * @param type the transform_type_t for the token + * @param algorithm the IKE id of the algorithm + * @param keysize the key size associated with the specific algorithm + */ + void (*register_token)(proposal_keywords_t *this, const char *name, + transform_type_t type, u_int16_t algorithm, + u_int16_t keysize); + + /** + * Destroy a proposal_keywords_t instance. + */ + void (*destroy)(proposal_keywords_t *this); +}; + +/** + * Create a proposal_keywords_t instance. + */ +proposal_keywords_t *proposal_keywords_create(); +#endif /** PROPOSAL_KEYWORDS_H_ @}*/ diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords.txt b/src/libstrongswan/crypto/proposal/proposal_keywords.txt deleted file mode 100644 index 1d04f2dc4..000000000 --- a/src/libstrongswan/crypto/proposal/proposal_keywords.txt +++ /dev/null @@ -1,153 +0,0 @@ -%{ -/* proposal keywords - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include -#include -#include -#include - -%} -struct proposal_token { - char *name; - transform_type_t type; - u_int16_t algorithm; - u_int16_t keysize; -}; -%% -null, ENCRYPTION_ALGORITHM, ENCR_NULL, 0 -des, ENCRYPTION_ALGORITHM, ENCR_DES, 0 -3des, ENCRYPTION_ALGORITHM, ENCR_3DES, 0 -aes, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128 -aes128, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128 -aes192, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192 -aes256, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256 -aes128ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128 -aes192ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192 -aes256ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256 -aes128ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 -aes128ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 -aes128ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 -aes128ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 -aes128ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 -aes128ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 -aes192ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 -aes192ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 -aes192ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 -aes192ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 -aes192ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 -aes192ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 -aes256ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 -aes256ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 -aes256ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 -aes256ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 -aes256ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 -aes256ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 -aes128gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 -aes128gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 -aes128gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 -aes128gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 -aes128gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 -aes128gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 -aes192gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 -aes192gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 -aes192gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 -aes192gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 -aes192gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 -aes192gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 -aes256gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 -aes256gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 -aes256gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 -aes256gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 -aes256gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 -aes256gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 -aes128gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128 -aes192gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192 -aes256gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256 -blowfish, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128 -blowfish128, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128 -blowfish192, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192 -blowfish256, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256 -camellia, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128 -camellia128, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128 -camellia192, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192 -camellia256, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256 -camellia128ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128 -camellia192ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192 -camellia256ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256 -camellia128ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128 -camellia128ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128 -camellia128ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128 -camellia128ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128 -camellia128ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128 -camellia128ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128 -camellia192ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192 -camellia192ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192 -camellia192ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192 -camellia192ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192 -camellia192ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192 -camellia192ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192 -camellia256ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256 -camellia256ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256 -camellia256ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256 -camellia256ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256 -camellia256ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256 -camellia256ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256 -cast128, ENCRYPTION_ALGORITHM, ENCR_CAST, 128 -serpent, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128 -serpent128, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128 -serpent192, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192 -serpent256, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256 -twofish, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128 -twofish128, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128 -twofish192, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192 -twofish256, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256 -sha, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 -sha1, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 -sha1_160, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0 -sha256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 -sha2_256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 -sha256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0 -sha2_256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0 -sha384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 -sha2_384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 -sha512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 -sha2_512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 -md5, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0 -md5_128, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0 -aesxcbc, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0 -camelliaxcbc, INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0 -aescmac, INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0 -modpnull, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0 -modp768, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0 -modp1024, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0 -modp1536, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0 -modp2048, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0 -modp3072, DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0 -modp4096, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0 -modp6144, DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0 -modp8192, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0 -ecp192, DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0 -ecp224, DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0 -ecp256, DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0 -ecp384, DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0 -ecp521, DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0 -modp1024s160, DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0 -modp2048s224, DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0 -modp2048s256, DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0 -noesn, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0 -esn, EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0 diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.c b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c new file mode 100644 index 000000000..ce52bc2ce --- /dev/null +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.c @@ -0,0 +1,324 @@ +/* C code produced by gperf version 3.0.3 */ +/* Command-line: /usr/bin/gperf -N proposal_get_token_static -m 10 -C -G -c -t -D */ +/* Computed positions: -k'1,5,7,10,15,$' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +error "gperf generated tables don't work with this execution character set. Please report a bug to ." +#endif + + +/* + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include +#include +#include +#include + +struct proposal_token { + char *name; + transform_type_t type; + u_int16_t algorithm; + u_int16_t keysize; +}; + +#define TOTAL_KEYWORDS 122 +#define MIN_WORD_LENGTH 3 +#define MAX_WORD_LENGTH 17 +#define MIN_HASH_VALUE 9 +#define MAX_HASH_VALUE 213 +/* maximum key range = 205, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (str, len) + register const char *str; + register unsigned int len; +{ + static const unsigned char asso_values[] = + { + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 14, 9, + 4, 34, 66, 19, 8, 4, 5, 3, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 131, 214, 3, 22, 21, + 3, 1, 101, 48, 3, 4, 214, 214, 3, 10, + 57, 4, 214, 214, 94, 6, 3, 32, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214 + }; + register int hval = len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[14]]; + /*FALLTHROUGH*/ + case 14: + case 13: + case 12: + case 11: + case 10: + hval += asso_values[(unsigned char)str[9]]; + /*FALLTHROUGH*/ + case 9: + case 8: + case 7: + hval += asso_values[(unsigned char)str[6]]; + /*FALLTHROUGH*/ + case 6: + case 5: + hval += asso_values[(unsigned char)str[4]]; + /*FALLTHROUGH*/ + case 4: + case 3: + case 2: + case 1: + hval += asso_values[(unsigned char)str[0]+1]; + break; + } + return hval + asso_values[(unsigned char)str[len - 1]]; +} + +static const struct proposal_token wordlist[] = + { + {"sha", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, + {"des", ENCRYPTION_ALGORITHM, ENCR_DES, 0}, + {"null", ENCRYPTION_ALGORITHM, ENCR_NULL, 0}, + {"sha1", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0}, + {"serpent", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, + {"camellia", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, + {"sha512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, + {"serpent192", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192}, + {"serpent128", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128}, + {"camellia192", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192}, + {"cast128", ENCRYPTION_ALGORITHM, ENCR_CAST, 128}, + {"camellia128", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128}, + {"aes", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, + {"serpent256", ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256}, + {"aes192", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192}, + {"sha256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, + {"aes128", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128}, + {"camellia192ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, + {"camellia128ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, + {"camellia192ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, + {"camellia128ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, + {"camellia192ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192}, + {"camellia128ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128}, + {"camellia192ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, + {"camellia128ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, + {"camellia192ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192}, + {"camellia128ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128}, + {"camellia256", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256}, + {"twofish", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, + {"camellia256ccm8", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, + {"aes256", ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256}, + {"camellia256ccm96", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, + {"twofish192", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192}, + {"camellia256ccm12", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256}, + {"twofish128", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128}, + {"camellia256ccm128",ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, + {"camellia256ccm16", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256}, + {"camelliaxcbc", INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0}, + {"twofish256", ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256}, + {"aes192ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, + {"aes128ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, + {"aes192ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, + {"aes128ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, + {"aes192ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192}, + {"aes128ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128}, + {"aes192ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, + {"aes128ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, + {"aes192ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192}, + {"aes128ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128}, + {"3des", ENCRYPTION_ALGORITHM, ENCR_3DES, 0}, + {"modp8192", DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0}, + {"modp768", DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0}, + {"md5", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0}, + {"sha384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0}, + {"aescmac", INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0}, + {"aes256ccm8", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, + {"md5_128", INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0}, + {"aes256ccm96", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, + {"aes256ccm12", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256}, + {"aes256ccm128", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, + {"aes256ccm16", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256}, + {"aesxcbc", INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0}, + {"aes192gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, + {"aes128gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, + {"aes192gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, + {"aes128gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, + {"aes192gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192}, + {"aes128gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128}, + {"aes192gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, + {"aes128gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, + {"aes192gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192}, + {"aes128gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128}, + {"camellia192ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192}, + {"camellia128ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128}, + {"modp1024s160", DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0}, + {"modp3072", DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0}, + {"aes256gcm8", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, + {"aes256gcm96", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, + {"aes256gcm12", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256}, + {"ecp192", DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0}, + {"aes256gcm128", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, + {"modp1536", DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0}, + {"aes256gcm16", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256}, + {"camellia256ccm64", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256}, + {"ecp521", DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0}, + {"camellia192ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192}, + {"camellia128ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128}, + {"noesn", EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0}, + {"aes192gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192}, + {"aes128gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128}, + {"modpnull", DIFFIE_HELLMAN_GROUP, MODP_NULL, 0}, + {"aes192ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192}, + {"aes128ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128}, + {"ecp256", DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0}, + {"camellia256ctr", ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256}, + {"blowfish", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, + {"modp2048", DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0}, + {"aes256gmac", ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256}, + {"modp4096", DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0}, + {"modp1024", DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0}, + {"blowfish192", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192}, + {"aes256ccm64", ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256}, + {"blowfish128", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128}, + {"aes192ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192}, + {"aes128ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128}, + {"modp2048s256", DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0}, + {"sha2_512", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0}, + {"aes192gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192}, + {"aes128gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128}, + {"esn", EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0}, + {"sha1_160", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0}, + {"aes256ctr", ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256}, + {"blowfish256", ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256}, + {"sha2_256", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0}, + {"sha256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, + {"aes256gcm64", ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256}, + {"sha2_256_96", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0}, + {"ecp224", DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0}, + {"ecp384", DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0}, + {"modp6144", DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0}, + {"modp2048s224", DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0}, + {"sha2_384", INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0} + }; + +static const short lookup[] = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, + 1, 2, -1, -1, -1, -1, 3, 4, -1, -1, + -1, 5, 6, -1, -1, 7, -1, 8, 9, 10, + 11, 12, -1, 13, -1, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + -1, -1, -1, -1, 29, 30, 31, 32, 33, 34, + 35, -1, 36, -1, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, -1, 58, -1, 59, -1, + 60, -1, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, -1, 75, -1, 76, + -1, 77, -1, 78, 79, 80, 81, 82, -1, 83, + 84, 85, 86, 87, -1, 88, 89, -1, 90, -1, + -1, 91, 92, -1, 93, -1, -1, 94, -1, 95, + 96, 97, 98, -1, 99, -1, 100, 101, 102, 103, + 104, 105, -1, -1, -1, 106, -1, -1, 107, 108, + -1, 109, -1, -1, 110, 111, 112, -1, -1, 113, + 114, -1, -1, -1, 115, 116, -1, 117, 118, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 119, -1, -1, -1, 120, + -1, -1, -1, 121 + }; + +#ifdef __GNUC__ +__inline +#ifdef __GNUC_STDC_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct proposal_token * +proposal_get_token_static (str, len) + register const char *str; + register unsigned int len; +{ + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register int index = lookup[key]; + + if (index >= 0) + { + register const char *s = wordlist[index].name; + + if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') + return &wordlist[index]; + } + } + } + return 0; +} diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.h b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h new file mode 100644 index 000000000..bc421dcc5 --- /dev/null +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef PROPOSAL_KEYWORDS_STATIC_H_ +#define PROPOSAL_KEYWORDS_STATIC_H_ + +#include "proposal_keywords.h" + +const proposal_token_t* proposal_get_token_static(register const char *str, + register unsigned int len); + +#endif /* PROPOSAL_KEYWORDS_STATIC_H_ */ + diff --git a/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt new file mode 100644 index 000000000..7f8c95757 --- /dev/null +++ b/src/libstrongswan/crypto/proposal/proposal_keywords_static.txt @@ -0,0 +1,153 @@ +%{ +/* + * Copyright (C) 2009 Andreas Steffen + * Hochschule fuer Technik Rapperswil, Switzerland + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include +#include +#include +#include + +%} +struct proposal_token { + char *name; + transform_type_t type; + u_int16_t algorithm; + u_int16_t keysize; +}; +%% +null, ENCRYPTION_ALGORITHM, ENCR_NULL, 0 +des, ENCRYPTION_ALGORITHM, ENCR_DES, 0 +3des, ENCRYPTION_ALGORITHM, ENCR_3DES, 0 +aes, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128 +aes128, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128 +aes192, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 192 +aes256, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256 +aes128ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 128 +aes192ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 192 +aes256ctr, ENCRYPTION_ALGORITHM, ENCR_AES_CTR, 256 +aes128ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 +aes128ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 128 +aes128ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 +aes128ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 128 +aes128ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 +aes128ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 128 +aes192ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 +aes192ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 192 +aes192ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 +aes192ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 192 +aes192ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 +aes192ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 192 +aes256ccm8, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 +aes256ccm64, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV8, 256 +aes256ccm12, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 +aes256ccm96, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV12, 256 +aes256ccm16, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 +aes256ccm128, ENCRYPTION_ALGORITHM, ENCR_AES_CCM_ICV16, 256 +aes128gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 +aes128gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 128 +aes128gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 +aes128gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 128 +aes128gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 +aes128gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 128 +aes192gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 +aes192gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 192 +aes192gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 +aes192gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 192 +aes192gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 +aes192gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 192 +aes256gcm8, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 +aes256gcm64, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV8, 256 +aes256gcm12, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 +aes256gcm96, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV12, 256 +aes256gcm16, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 +aes256gcm128, ENCRYPTION_ALGORITHM, ENCR_AES_GCM_ICV16, 256 +aes128gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 128 +aes192gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 192 +aes256gmac, ENCRYPTION_ALGORITHM, ENCR_NULL_AUTH_AES_GMAC, 256 +blowfish, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128 +blowfish128, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 128 +blowfish192, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 192 +blowfish256, ENCRYPTION_ALGORITHM, ENCR_BLOWFISH, 256 +camellia, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128 +camellia128, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 128 +camellia192, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 192 +camellia256, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CBC, 256 +camellia128ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 128 +camellia192ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 192 +camellia256ctr, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CTR, 256 +camellia128ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128 +camellia128ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 128 +camellia128ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128 +camellia128ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 128 +camellia128ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128 +camellia128ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 128 +camellia192ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192 +camellia192ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 192 +camellia192ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192 +camellia192ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 192 +camellia192ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192 +camellia192ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 192 +camellia256ccm8, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256 +camellia256ccm64, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV8, 256 +camellia256ccm12, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256 +camellia256ccm96, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV12, 256 +camellia256ccm16, ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256 +camellia256ccm128,ENCRYPTION_ALGORITHM, ENCR_CAMELLIA_CCM_ICV16, 256 +cast128, ENCRYPTION_ALGORITHM, ENCR_CAST, 128 +serpent, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128 +serpent128, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 128 +serpent192, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 192 +serpent256, ENCRYPTION_ALGORITHM, ENCR_SERPENT_CBC, 256 +twofish, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128 +twofish128, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 128 +twofish192, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 192 +twofish256, ENCRYPTION_ALGORITHM, ENCR_TWOFISH_CBC, 256 +sha, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 +sha1, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0 +sha1_160, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_160, 0 +sha256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 +sha2_256, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_128, 0 +sha256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0 +sha2_256_96, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_256_96, 0 +sha384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 +sha2_384, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_384_192, 0 +sha512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 +sha2_512, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA2_512_256, 0 +md5, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0 +md5_128, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_128, 0 +aesxcbc, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0 +camelliaxcbc, INTEGRITY_ALGORITHM, AUTH_CAMELLIA_XCBC_96, 0 +aescmac, INTEGRITY_ALGORITHM, AUTH_AES_CMAC_96, 0 +modpnull, DIFFIE_HELLMAN_GROUP, MODP_NULL, 0 +modp768, DIFFIE_HELLMAN_GROUP, MODP_768_BIT, 0 +modp1024, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0 +modp1536, DIFFIE_HELLMAN_GROUP, MODP_1536_BIT, 0 +modp2048, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0 +modp3072, DIFFIE_HELLMAN_GROUP, MODP_3072_BIT, 0 +modp4096, DIFFIE_HELLMAN_GROUP, MODP_4096_BIT, 0 +modp6144, DIFFIE_HELLMAN_GROUP, MODP_6144_BIT, 0 +modp8192, DIFFIE_HELLMAN_GROUP, MODP_8192_BIT, 0 +ecp192, DIFFIE_HELLMAN_GROUP, ECP_192_BIT, 0 +ecp224, DIFFIE_HELLMAN_GROUP, ECP_224_BIT, 0 +ecp256, DIFFIE_HELLMAN_GROUP, ECP_256_BIT, 0 +ecp384, DIFFIE_HELLMAN_GROUP, ECP_384_BIT, 0 +ecp521, DIFFIE_HELLMAN_GROUP, ECP_521_BIT, 0 +modp1024s160, DIFFIE_HELLMAN_GROUP, MODP_1024_160, 0 +modp2048s224, DIFFIE_HELLMAN_GROUP, MODP_2048_224, 0 +modp2048s256, DIFFIE_HELLMAN_GROUP, MODP_2048_256, 0 +noesn, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0 +esn, EXTENDED_SEQUENCE_NUMBERS, EXT_SEQ_NUMBERS, 0 diff --git a/src/libstrongswan/crypto/rngs/rng.c b/src/libstrongswan/crypto/rngs/rng.c index 67fd76910..f8fd50d3f 100644 --- a/src/libstrongswan/crypto/rngs/rng.c +++ b/src/libstrongswan/crypto/rngs/rng.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -20,3 +21,43 @@ ENUM(rng_quality_names, RNG_WEAK, RNG_TRUE, "RNG_STRONG", "RNG_TRUE", ); + +/* + * Described in header. + */ +bool rng_get_bytes_not_zero(rng_t *rng, size_t len, u_int8_t *buffer, bool all) +{ + u_int8_t *pos = buffer, *check = buffer + (all ? len : min(1, len)); + + if (!rng->get_bytes(rng, len, pos)) + { + return FALSE; + } + + for (; pos < check; pos++) + { + while (*pos == 0) + { + if (!rng->get_bytes(rng, 1, pos)) + { + return FALSE; + } + } + } + return TRUE; +} + +/* + * Described in header. + */ +bool rng_allocate_bytes_not_zero(rng_t *rng, size_t len, chunk_t *chunk, + bool all) +{ + *chunk = chunk_alloc(len); + if (!rng_get_bytes_not_zero(rng, len, chunk->ptr, all)) + { + chunk_clear(chunk); + return FALSE; + } + return TRUE; +} diff --git a/src/libstrongswan/crypto/rngs/rng.h b/src/libstrongswan/crypto/rngs/rng.h index 36ef52bb4..aee829d71 100644 --- a/src/libstrongswan/crypto/rngs/rng.h +++ b/src/libstrongswan/crypto/rngs/rng.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -53,21 +54,53 @@ struct rng_t { * * @param len number of bytes to get * @param buffer pointer where the generated bytes will be written + * @return TRUE if bytes successfully written */ - void (*get_bytes) (rng_t *this, size_t len, u_int8_t *buffer); + bool (*get_bytes)(rng_t *this, size_t len, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generates random bytes and allocate space for them. * * @param len number of bytes to get * @param chunk chunk which will hold generated bytes + * @return TRUE if allocation succeeded */ - void (*allocate_bytes) (rng_t *this, size_t len, chunk_t *chunk); + bool (*allocate_bytes)(rng_t *this, size_t len, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Destroys a rng object. */ - void (*destroy) (rng_t *this); + void (*destroy)(rng_t *this); }; +/** + * Wrapper around rng_t.get_bytes() ensuring that either all bytes or at least + * the first byte is not zero. + * + * @param rng rng_t object + * @param len number of bytes to get + * @param buffer pointer where the generated bytes will be written + * @param all TRUE if all bytes have to be non-zero, FALSE for first + * @return TRUE if bytes successfully written + */ +bool rng_get_bytes_not_zero(rng_t *rng, size_t len, u_int8_t *buffer, + bool all) __attribute__((warn_unused_result)); + +/** + * Wrapper around rng_t.allocate_bytes() ensuring that either all bytes or at + * least the first byte is not zero. + * + * @param rng rng_t object + * @param len number of bytes to get + * @param chunk chunk that stores the generated bytes (allocated) + * @param all TRUE if all bytes have to be non-zero, FALSE for first + * @return TRUE if bytes successfully written + */ +bool rng_allocate_bytes_not_zero(rng_t *rng, size_t len, chunk_t *chunk, + bool all) __attribute__((warn_unused_result)); + + + #endif /** RNG_H_ @}*/ diff --git a/src/libstrongswan/crypto/signers/mac_signer.c b/src/libstrongswan/crypto/signers/mac_signer.c new file mode 100644 index 000000000..7c52aa305 --- /dev/null +++ b/src/libstrongswan/crypto/signers/mac_signer.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2008 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "mac_signer.h" + +typedef struct private_signer_t private_signer_t; + +/** + * Private data of a mac_signer_t object. + */ +struct private_signer_t { + + /** + * Public interface + */ + signer_t public; + + /** + * MAC to use + */ + mac_t *mac; + + /** + * Truncation of MAC output + */ + size_t truncation; +}; + +METHOD(signer_t, get_signature, bool, + private_signer_t *this, chunk_t data, u_int8_t *buffer) +{ + if (buffer) + { + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (!this->mac->get_mac(this->mac, data, mac)) + { + return FALSE; + } + memcpy(buffer, mac, this->truncation); + return TRUE; + } + return this->mac->get_mac(this->mac, data, NULL); +} + +METHOD(signer_t, allocate_signature, bool, + private_signer_t *this, chunk_t data, chunk_t *chunk) +{ + if (chunk) + { + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (!this->mac->get_mac(this->mac, data, mac)) + { + return FALSE; + } + *chunk = chunk_alloc(this->truncation); + memcpy(chunk->ptr, mac, this->truncation); + return TRUE; + } + return this->mac->get_mac(this->mac, data, NULL); +} + +METHOD(signer_t, verify_signature, bool, + private_signer_t *this, chunk_t data, chunk_t signature) +{ + u_int8_t mac[this->mac->get_mac_size(this->mac)]; + + if (signature.len != this->truncation) + { + return FALSE; + } + return this->mac->get_mac(this->mac, data, mac) && + memeq(signature.ptr, mac, this->truncation); +} + +METHOD(signer_t, get_key_size, size_t, + private_signer_t *this) +{ + return this->mac->get_mac_size(this->mac); +} + +METHOD(signer_t, get_block_size, size_t, + private_signer_t *this) +{ + return this->truncation; +} + +METHOD(signer_t, set_key, bool, + private_signer_t *this, chunk_t key) +{ + return this->mac->set_key(this->mac, key); +} + +METHOD(signer_t, destroy, void, + private_signer_t *this) +{ + this->mac->destroy(this->mac); + free(this); +} + +/* + * Described in header + */ +signer_t *mac_signer_create(mac_t *mac, size_t len) +{ + private_signer_t *this; + + INIT(this, + .public = { + .get_signature = _get_signature, + .allocate_signature = _allocate_signature, + .verify_signature = _verify_signature, + .get_block_size = _get_block_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _destroy, + }, + .truncation = min(len, mac->get_mac_size(mac)), + .mac = mac, + ); + + return &this->public; +} + diff --git a/src/libstrongswan/crypto/signers/mac_signer.h b/src/libstrongswan/crypto/signers/mac_signer.h new file mode 100644 index 000000000..a50c8cadf --- /dev/null +++ b/src/libstrongswan/crypto/signers/mac_signer.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mac_signer mac_signer + * @{ @ingroup crypto + */ + +#ifndef MAC_SIGNER_H_ +#define MAC_SIGNER_H_ + +typedef struct mac_signer_t mac_signer_t; + +#include +#include + +/** + * Creates an implementation of the signer_t interface using the provided mac_t + * implementation and truncation length. + * + * @note len will be set to mac_t.get_mac_size() if it is greater than that. + * + * @param mac mac_t implementation + * @param len length of resulting signature + * @return mac_signer_t + */ +signer_t *mac_signer_create(mac_t *mac, size_t len); + +#endif /** MAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/crypto/signers/signer.h b/src/libstrongswan/crypto/signers/signer.h index c6870e475..9b6bd479a 100644 --- a/src/libstrongswan/crypto/signers/signer.h +++ b/src/libstrongswan/crypto/signers/signer.h @@ -91,8 +91,10 @@ struct signer_t { * * @param data a chunk containing the data to sign * @param buffer pointer where the signature will be written + * @return TRUE if signature created successfully */ - void (*get_signature) (signer_t *this, chunk_t data, u_int8_t *buffer); + bool (*get_signature)(signer_t *this, chunk_t data, + u_int8_t *buffer) __attribute__((warn_unused_result)); /** * Generate a signature and allocate space for it. @@ -102,8 +104,10 @@ struct signer_t { * * @param data a chunk containing the data to sign * @param chunk chunk which will hold the allocated signature + * @return TRUE if signature allocated successfully */ - void (*allocate_signature) (signer_t *this, chunk_t data, chunk_t *chunk); + bool (*allocate_signature)(signer_t *this, chunk_t data, + chunk_t *chunk) __attribute__((warn_unused_result)); /** * Verify a signature. @@ -116,33 +120,35 @@ struct signer_t { * @param signature a chunk containing the signature * @return TRUE, if signature is valid, FALSE otherwise */ - bool (*verify_signature) (signer_t *this, chunk_t data, chunk_t signature); + bool (*verify_signature)(signer_t *this, chunk_t data, chunk_t signature); /** * Get the block size of this signature algorithm. * * @return block size in bytes */ - size_t (*get_block_size) (signer_t *this); + size_t (*get_block_size)(signer_t *this); /** * Get the key size of the signature algorithm. * * @return key size in bytes */ - size_t (*get_key_size) (signer_t *this); + size_t (*get_key_size)(signer_t *this); /** * Set the key for this object. * * @param key key to set + * @return TRUE if key set */ - void (*set_key) (signer_t *this, chunk_t key); + bool (*set_key)(signer_t *this, + chunk_t key) __attribute__((warn_unused_result)); /** * Destroys a signer_t object. */ - void (*destroy) (signer_t *this); + void (*destroy)(signer_t *this); }; #endif /** SIGNER_H_ @}*/ diff --git a/src/libstrongswan/crypto/transform.c b/src/libstrongswan/crypto/transform.c index 1e108f1de..56252971a 100644 --- a/src/libstrongswan/crypto/transform.c +++ b/src/libstrongswan/crypto/transform.c @@ -15,12 +15,13 @@ #include -ENUM_BEGIN(transform_type_names, UNDEFINED_TRANSFORM_TYPE, AEAD_ALGORITHM, +ENUM_BEGIN(transform_type_names, UNDEFINED_TRANSFORM_TYPE, COMPRESSION_ALGORITHM, "UNDEFINED_TRANSFORM_TYPE", "HASH_ALGORITHM", "RANDOM_NUMBER_GENERATOR", - "AEAD_ALGORITHM"); -ENUM_NEXT(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS, AEAD_ALGORITHM, + "AEAD_ALGORITHM", + "COMPRESSION_ALGORITHM"); +ENUM_NEXT(transform_type_names, ENCRYPTION_ALGORITHM, EXTENDED_SEQUENCE_NUMBERS, COMPRESSION_ALGORITHM, "ENCRYPTION_ALGORITHM", "PSEUDO_RANDOM_FUNCTION", "INTEGRITY_ALGORITHM", diff --git a/src/libstrongswan/crypto/transform.h b/src/libstrongswan/crypto/transform.h index 1393c674c..311df068f 100644 --- a/src/libstrongswan/crypto/transform.h +++ b/src/libstrongswan/crypto/transform.h @@ -23,7 +23,7 @@ typedef enum transform_type_t transform_type_t; -#include +#include /** * Type of a transform, as in IKEv2 RFC 3.3.2. @@ -33,6 +33,7 @@ enum transform_type_t { HASH_ALGORITHM = 242, RANDOM_NUMBER_GENERATOR = 243, AEAD_ALGORITHM = 244, + COMPRESSION_ALGORITHM = 245, ENCRYPTION_ALGORITHM = 1, PSEUDO_RANDOM_FUNCTION = 2, INTEGRITY_ALGORITHM = 3, diff --git a/src/libstrongswan/debug.c b/src/libstrongswan/debug.c index d6c5b06b6..e8c9e6b98 100644 --- a/src/libstrongswan/debug.c +++ b/src/libstrongswan/debug.c @@ -33,6 +33,8 @@ ENUM(debug_names, DBG_DMN, DBG_LIB, "IMV", "PTS", "TLS", + "APP", + "ESP", "LIB", ); @@ -52,6 +54,8 @@ ENUM(debug_lower_names, DBG_DMN, DBG_LIB, "imv", "pts", "tls", + "app", + "esp", "lib", ); diff --git a/src/libstrongswan/debug.h b/src/libstrongswan/debug.h index 2a6ff98ad..ff4b4a1e9 100644 --- a/src/libstrongswan/debug.h +++ b/src/libstrongswan/debug.h @@ -62,6 +62,10 @@ enum debug_t { DBG_PTS, /** libtls */ DBG_TLS, + /** applications other than daemons */ + DBG_APP, + /** libipsec */ + DBG_ESP, /** libstrongswan */ DBG_LIB, /** number of groups */ diff --git a/src/libstrongswan/eap/eap.c b/src/libstrongswan/eap/eap.c index efd3ee981..1e4cf11bf 100644 --- a/src/libstrongswan/eap/eap.c +++ b/src/libstrongswan/eap/eap.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2006 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -13,8 +14,13 @@ * for more details. */ +#include +#include + #include "eap.h" +#include + ENUM(eap_code_names, EAP_REQUEST, EAP_FAILURE, "EAP_REQUEST", "EAP_RESPONSE", @@ -51,12 +57,12 @@ ENUM_NEXT(eap_type_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "EAP_MSTLV"); ENUM_NEXT(eap_type_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "EAP_TNC"); -ENUM_NEXT(eap_type_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "EAP_DYNAMIC", - "EAP_RADIUS", +ENUM_NEXT(eap_type_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EAP_EXPANDED", - "EAP_EXPERIMENTAL"); -ENUM_END(eap_type_names, EAP_EXPERIMENTAL); + "EAP_EXPERIMENTAL", + "EAP_RADIUS", + "EAP_DYNAMIC"); +ENUM_END(eap_type_names, EAP_DYNAMIC); ENUM_BEGIN(eap_type_short_names, EAP_IDENTITY, EAP_GTC, "ID", @@ -80,12 +86,12 @@ ENUM_NEXT(eap_type_short_names, EAP_MSTLV, EAP_MSTLV, EAP_MSCHAPV2, "MSTLV"); ENUM_NEXT(eap_type_short_names, EAP_TNC, EAP_TNC, EAP_MSTLV, "TNC"); -ENUM_NEXT(eap_type_short_names, EAP_DYNAMIC, EAP_EXPERIMENTAL, EAP_TNC, - "DYN", - "RAD", +ENUM_NEXT(eap_type_short_names, EAP_EXPANDED, EAP_DYNAMIC, EAP_TNC, "EXP", - "XP"); -ENUM_END(eap_type_short_names, EAP_EXPERIMENTAL); + "XP", + "RAD", + "DYN"); +ENUM_END(eap_type_short_names, EAP_DYNAMIC); /* * See header @@ -108,6 +114,7 @@ eap_type_t eap_type_from_string(char *name) {"peap", EAP_PEAP}, {"mschapv2", EAP_MSCHAPV2}, {"tnc", EAP_TNC}, + {"dynamic", EAP_DYNAMIC}, {"radius", EAP_RADIUS}, }; @@ -120,3 +127,56 @@ eap_type_t eap_type_from_string(char *name) } return 0; } + +/* + * See header + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str) +{ + enumerator_t *enumerator; + eap_vendor_type_t *result = NULL; + eap_type_t type = 0; + u_int32_t vendor = 0; + char *part, *end; + + /* parse EAP method string of the form: [eap-]type[-vendor] */ + enumerator = enumerator_create_token(str, "-", " "); + while (enumerator->enumerate(enumerator, &part)) + { + if (!type) + { + if (streq(part, "eap")) + { /* skip 'eap' at the beginning */ + continue; + } + type = eap_type_from_string(part); + if (!type) + { + type = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "unknown or invalid EAP method: %s", part); + break; + } + } + continue; + } + vendor = strtoul(part, &end, 0); + if (*end != '\0' || errno) + { + DBG1(DBG_LIB, "invalid EAP vendor: %s", part); + type = 0; + } + break; + } + enumerator->destroy(enumerator); + + if (type) + { + INIT(result, + .type = type, + .vendor = vendor, + ); + } + return result; +} diff --git a/src/libstrongswan/eap/eap.h b/src/libstrongswan/eap/eap.h index 945e4bc59..0e144b123 100644 --- a/src/libstrongswan/eap/eap.h +++ b/src/libstrongswan/eap/eap.h @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG + * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -14,7 +16,7 @@ */ /** - * @defgroup eap eap + * @defgroup leap eap * @{ @ingroup libstrongswan */ @@ -23,6 +25,7 @@ typedef enum eap_code_t eap_code_t; typedef enum eap_type_t eap_type_t; +typedef struct eap_vendor_type_t eap_vendor_type_t; #include @@ -62,14 +65,14 @@ enum eap_type_t { EAP_AKA = 23, EAP_PEAP = 25, EAP_MSCHAPV2 = 26, - EAP_MSTLV = 33, + EAP_MSTLV = 33, EAP_TNC = 38, - /** select EAP method dynamically based on i.e. EAP-Identity */ - EAP_DYNAMIC = 252, - /** not a method, but an implementation providing different methods */ - EAP_RADIUS = 253, EAP_EXPANDED = 254, EAP_EXPERIMENTAL = 255, + /** not a method, but an implementation providing different methods */ + EAP_RADIUS = 256, + /** not a method, select method dynamically based on client selection */ + EAP_DYNAMIC = 257, }; /** @@ -82,6 +85,22 @@ extern enum_name_t *eap_type_names; */ extern enum_name_t *eap_type_short_names; +/** + * Struct that stores EAP type and vendor ID + */ +struct eap_vendor_type_t { + + /** + * EAP type + */ + eap_type_t type; + + /** + * Vendor Id + */ + u_int32_t vendor; +}; + /** * EAP packet format */ @@ -101,4 +120,12 @@ typedef struct __attribute__((packed)) { */ eap_type_t eap_type_from_string(char *name); +/** + * Parse a string of the form [eap-]type[-vendor]. + * + * @param str EAP method string + * @return parsed type (gets allocated), NULL if unknown or failed + */ +eap_vendor_type_t *eap_vendor_type_from_string(char *str); + #endif /** EAP_H_ @}*/ diff --git a/src/libstrongswan/enum.c b/src/libstrongswan/enum.c index 5c811bd17..2dc7c5dde 100644 --- a/src/libstrongswan/enum.c +++ b/src/libstrongswan/enum.c @@ -60,7 +60,7 @@ int enum_from_name(enum_name_t *e, char *name) /** * Described in header. */ -int enum_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { enum_name_t *ed = *((enum_name_t**)(args[0])); @@ -70,10 +70,10 @@ int enum_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (name == NULL) { - return print_in_hook(dst, len, "(%d)", val); + return print_in_hook(data, "(%d)", val); } else { - return print_in_hook(dst, len, "%s", name); + return print_in_hook(data, "%s", name); } } diff --git a/src/libstrongswan/enum.h b/src/libstrongswan/enum.h index d5f169772..840371245 100644 --- a/src/libstrongswan/enum.h +++ b/src/libstrongswan/enum.h @@ -130,7 +130,7 @@ int enum_from_name(enum_name_t *e, char *name); * Arguments are: * enum_names_t *names, int value */ -int enum_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int enum_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** ENUM_H_ @}*/ diff --git a/src/libstrongswan/ipsec/ipsec_types.c b/src/libstrongswan/ipsec/ipsec_types.c new file mode 100644 index 000000000..e4e927313 --- /dev/null +++ b/src/libstrongswan/ipsec/ipsec_types.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ipsec_types.h" + +ENUM(ipsec_mode_names, MODE_TRANSPORT, MODE_DROP, + "TRANSPORT", + "TUNNEL", + "BEET", + "PASS", + "DROP" +); + +ENUM(policy_dir_names, POLICY_IN, POLICY_FWD, + "in", + "out", + "fwd" +); + +ENUM(ipcomp_transform_names, IPCOMP_NONE, IPCOMP_LZJH, + "IPCOMP_NONE", + "IPCOMP_OUI", + "IPCOMP_DEFLATE", + "IPCOMP_LZS", + "IPCOMP_LZJH" +); diff --git a/src/libstrongswan/ipsec/ipsec_types.h b/src/libstrongswan/ipsec/ipsec_types.h new file mode 100644 index 000000000..32e55bc50 --- /dev/null +++ b/src/libstrongswan/ipsec/ipsec_types.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ipsec_types ipsec_types + * @{ @ingroup ipsec + */ + +#ifndef IPSEC_TYPES_H_ +#define IPSEC_TYPES_H_ + +typedef enum ipsec_mode_t ipsec_mode_t; +typedef enum policy_dir_t policy_dir_t; +typedef enum policy_type_t policy_type_t; +typedef enum policy_priority_t policy_priority_t; +typedef enum ipcomp_transform_t ipcomp_transform_t; +typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t; +typedef struct lifetime_cfg_t lifetime_cfg_t; +typedef struct mark_t mark_t; + +#include + +/** + * Mode of an IPsec SA. + */ +enum ipsec_mode_t { + /** not using any encapsulation */ + MODE_NONE = 0, + /** transport mode, no inner address */ + MODE_TRANSPORT = 1, + /** tunnel mode, inner and outer addresses */ + MODE_TUNNEL, + /** BEET mode, tunnel mode but fixed, bound inner addresses */ + MODE_BEET, + /** passthrough policy for traffic without an IPsec SA */ + MODE_PASS, + /** drop policy discarding traffic */ + MODE_DROP +}; + +/** + * enum names for ipsec_mode_t. + */ +extern enum_name_t *ipsec_mode_names; + +/** + * Direction of a policy. These are equal to those + * defined in xfrm.h, but we want to stay implementation + * neutral here. + */ +enum policy_dir_t { + /** Policy for inbound traffic */ + POLICY_IN = 0, + /** Policy for outbound traffic */ + POLICY_OUT = 1, + /** Policy for forwarded traffic */ + POLICY_FWD = 2, +}; + +/** + * enum names for policy_dir_t. + */ +extern enum_name_t *policy_dir_names; + +/** + * Type of a policy. + */ +enum policy_type_t { + /** Normal IPsec policy */ + POLICY_IPSEC = 1, + /** Passthrough policy (traffic is ignored by IPsec) */ + POLICY_PASS, + /** Drop policy (traffic is discarded) */ + POLICY_DROP, +}; + +/** + * High-level priority of a policy. + */ +enum policy_priority_t { + /** Default priority */ + POLICY_PRIORITY_DEFAULT, + /** Priority for trap policies */ + POLICY_PRIORITY_ROUTED, + /** Priority for fallback drop policies */ + POLICY_PRIORITY_FALLBACK, +}; + +/** + * IPComp transform IDs, as in RFC 4306 + */ +enum ipcomp_transform_t { + IPCOMP_NONE = 0, + IPCOMP_OUI = 1, + IPCOMP_DEFLATE = 2, + IPCOMP_LZS = 3, + IPCOMP_LZJH = 4, +}; + +/** + * enum strings for ipcomp_transform_t. + */ +extern enum_name_t *ipcomp_transform_names; + +/** + * This struct contains details about IPsec SA(s) tied to a policy. + */ +struct ipsec_sa_cfg_t { + /** mode of SA (tunnel, transport) */ + ipsec_mode_t mode; + /** unique ID */ + u_int32_t reqid; + /** details about ESP/AH */ + struct { + /** TRUE if this protocol is used */ + bool use; + /** SPI for ESP/AH */ + u_int32_t spi; + } esp, ah; + /** details about IPComp */ + struct { + /** the IPComp transform used */ + u_int16_t transform; + /** CPI for IPComp */ + u_int16_t cpi; + } ipcomp; +}; + +/** + * A lifetime_cfg_t defines the lifetime limits of an SA. + * + * Set any of these values to 0 to ignore. + */ +struct lifetime_cfg_t { + struct { + /** Limit before the SA gets invalid. */ + u_int64_t life; + /** Limit before the SA gets rekeyed. */ + u_int64_t rekey; + /** The range of a random value subtracted from rekey. */ + u_int64_t jitter; + } time, bytes, packets; +}; + +/** + * A mark_t defines an optional mark in an IPsec SA. + */ +struct mark_t { + /** Mark value */ + u_int32_t value; + /** Mark mask */ + u_int32_t mask; +}; + +/** + * Special mark value that uses the reqid of the CHILD_SA as mark + */ +#define MARK_REQID (0xFFFFFFFF) + +#endif /** IPSEC_TYPES_H_ @}*/ diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index cd6a41f44..1179b468c 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #define CHECKSUM_LIBRARY IPSEC_LIB_DIR"/libchecksum.so" @@ -72,6 +73,7 @@ void library_deinit() this->public.creds->destroy(this->public.creds); this->public.encoding->destroy(this->public.encoding); this->public.crypto->destroy(this->public.crypto); + this->public.proposal->destroy(this->public.proposal); this->public.fetcher->destroy(this->public.fetcher); this->public.db->destroy(this->public.db); this->public.printf_hook->destroy(this->public.printf_hook); @@ -88,6 +90,7 @@ void library_deinit() } threads_deinit(); + backtrace_deinit(); free(this); lib = NULL; @@ -146,6 +149,7 @@ bool library_init(char *settings) ); lib = &this->public; + backtrace_init(); threads_init(); #ifdef LEAK_DETECTIVE @@ -179,6 +183,7 @@ bool library_init(char *settings) this->objects = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 4); this->public.settings = settings_create(settings); + this->public.proposal = proposal_keywords_create(); this->public.crypto = crypto_factory_create(); this->public.creds = credential_factory_create(); this->public.credmgr = credential_manager_create(); @@ -204,6 +209,7 @@ bool library_init(char *settings) return FALSE; #endif /* INTEGRITY_TEST */ } + return TRUE; } diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 7e76e1927..b79bd91be 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -43,6 +43,9 @@ * @defgroup fetcher fetcher * @ingroup libstrongswan * + * @defgroup ipsec ipsec + * @ingroup libstrongswan + * * @defgroup plugins plugins * @ingroup libstrongswan * @@ -67,6 +70,10 @@ #ifndef LIBRARY_H_ #define LIBRARY_H_ +#ifndef CONFIG_H_INCLUDED +# error config.h not included, pass "-include [...]/config.h" to gcc +#endif + #include "printf_hook.h" #include "utils.h" #include "chunk.h" @@ -75,6 +82,7 @@ #include "processing/processor.h" #include "processing/scheduler.h" #include "crypto/crypto_factory.h" +#include "crypto/proposal/proposal_keywords.h" #include "fetcher/fetcher_manager.h" #include "database/database_factory.h" #include "credentials/credential_factory.h" @@ -112,6 +120,11 @@ struct library_t { */ printf_hook_t *printf_hook; + /** + * Proposal keywords registry + */ + proposal_keywords_t *proposal; + /** * crypto algorithm registry and factory */ diff --git a/src/libstrongswan/pen/pen.c b/src/libstrongswan/pen/pen.c index 3dd92218d..a80e949e3 100644 --- a/src/libstrongswan/pen/pen.c +++ b/src/libstrongswan/pen/pen.c @@ -17,7 +17,9 @@ ENUM_BEGIN(pen_names, PEN_IETF, PEN_IETF, "IETF"); -ENUM_NEXT(pen_names, PEN_MICROSOFT, PEN_MICROSOFT, PEN_IETF, +ENUM_NEXT(pen_names, PEN_IBM, PEN_IBM, PEN_IETF, + "IBM"); +ENUM_NEXT(pen_names, PEN_MICROSOFT, PEN_MICROSOFT, PEN_IBM, "Microsoft"); ENUM_NEXT(pen_names, PEN_OSC, PEN_OSC, PEN_MICROSOFT, "OSC"); @@ -27,7 +29,9 @@ ENUM_NEXT(pen_names, PEN_FHH, PEN_FHH, PEN_TCG, "FHH"); ENUM_NEXT(pen_names, PEN_ITA, PEN_ITA, PEN_FHH, "ITA-HSR"); -ENUM_NEXT(pen_names, PEN_RESERVED, PEN_RESERVED, PEN_ITA, +ENUM_NEXT(pen_names, PEN_OPENPTS, PEN_OPENPTS, PEN_ITA, + "OpenPTS"); +ENUM_NEXT(pen_names, PEN_RESERVED, PEN_RESERVED, PEN_OPENPTS, "Reserved"); ENUM_END(pen_names, PEN_RESERVED); diff --git a/src/libstrongswan/pen/pen.h b/src/libstrongswan/pen/pen.h index 396cc7199..78b6e4df2 100644 --- a/src/libstrongswan/pen/pen.h +++ b/src/libstrongswan/pen/pen.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Andreas Steffen + * Copyright (C) 2011-2012 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -27,17 +27,37 @@ #include typedef enum pen_t pen_t; +typedef struct pen_type_t pen_type_t; enum pen_t { PEN_IETF = 0x000000, /* 0 */ + PEN_IBM = 0x000002, /* 2 */ PEN_MICROSOFT = 0x000137, /* 311 */ PEN_OSC = 0x002358, /* 9048 */ PEN_TCG = 0x005597, /* 21911 */ PEN_FHH = 0x0080ab, /* 32939 */ PEN_ITA = 0x00902a, /* 36906 */ + PEN_OPENPTS = 0x00950e, /* 38158 */ PEN_RESERVED = 0xffffff, /* 16777215 */ }; +/** + * Vendor specific type + */ +struct pen_type_t { + pen_t vendor_id; + u_int32_t type; +}; + +/** + * Create a pen_type_t struct + */ +static inline pen_type_t pen_type_create(pen_t vendor_id, u_int32_t type) +{ + pen_type_t pen_type = {vendor_id, type}; + return pen_type; +} + /** * enum names for pen_t. */ diff --git a/src/libstrongswan/plugins/aes/Makefile.in b/src/libstrongswan/plugins/aes/Makefile.in index 53eecbe8d..c09cf66a7 100644 --- a/src/libstrongswan/plugins/aes/Makefile.in +++ b/src/libstrongswan/plugins/aes/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_aes_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_aes_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_aes_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_aes_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/aes/aes_crypter.c b/src/libstrongswan/plugins/aes/aes_crypter.c index 2a1fed944..6b3d03cea 100644 --- a/src/libstrongswan/plugins/aes/aes_crypter.c +++ b/src/libstrongswan/plugins/aes/aes_crypter.c @@ -1331,7 +1331,7 @@ static void decrypt_block(const private_aes_crypter_t *this, const unsigned char state_out(out_blk, b0); } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) { int pos; @@ -1371,9 +1371,10 @@ METHOD(crypter_t, decrypt, void, out-=16; pos-=16; } + return TRUE; } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) { int pos; @@ -1408,6 +1409,7 @@ METHOD(crypter_t, encrypt, void, out+=16; pos+=16; } + return TRUE; } METHOD(crypter_t, get_block_size, size_t, @@ -1428,7 +1430,7 @@ METHOD(crypter_t, get_key_size, size_t, return this->key_size; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_aes_crypter_t *this, chunk_t key) { u_int32_t *kf, *kt, rci, f = 0; @@ -1513,6 +1515,7 @@ METHOD(crypter_t, set_key, void, } cpy(kt, kf); } + return TRUE; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/af_alg/Makefile.in b/src/libstrongswan/plugins/af_alg/Makefile.in index 679e883e1..d3da24718 100644 --- a/src/libstrongswan/plugins/af_alg/Makefile.in +++ b/src/libstrongswan/plugins/af_alg/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_af_alg_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_af_alg_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_af_alg_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/af_alg/af_alg_crypter.c b/src/libstrongswan/plugins/af_alg/af_alg_crypter.c index 9c547140d..5d0976d95 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_crypter.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_crypter.c @@ -131,32 +131,26 @@ static size_t lookup_alg(encryption_algorithm_t algo, char **name, return 0; } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_af_alg_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { if (dst) { *dst = chunk_alloc(data.len); - this->ops->crypt(this->ops, ALG_OP_DECRYPT, iv, data, dst->ptr); - } - else - { - this->ops->crypt(this->ops, ALG_OP_DECRYPT, iv, data, data.ptr); + return this->ops->crypt(this->ops, ALG_OP_DECRYPT, iv, data, dst->ptr); } + return this->ops->crypt(this->ops, ALG_OP_DECRYPT, iv, data, data.ptr); } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_af_alg_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { if (dst) { *dst = chunk_alloc(data.len); - this->ops->crypt(this->ops, ALG_OP_ENCRYPT, iv, data, dst->ptr); - } - else - { - this->ops->crypt(this->ops, ALG_OP_ENCRYPT, iv, data, data.ptr); + return this->ops->crypt(this->ops, ALG_OP_ENCRYPT, iv, data, dst->ptr); } + return this->ops->crypt(this->ops, ALG_OP_ENCRYPT, iv, data, data.ptr); } METHOD(crypter_t, get_block_size, size_t, @@ -177,10 +171,10 @@ METHOD(crypter_t, get_key_size, size_t, return this->keymat_size; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_af_alg_crypter_t *this, chunk_t key) { - this->ops->set_key(this->ops, key); + return this->ops->set_key(this->ops, key); } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/af_alg/af_alg_hasher.c b/src/libstrongswan/plugins/af_alg/af_alg_hasher.c index ef2350497..47a6e5e0e 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_hasher.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_hasher.c @@ -99,30 +99,28 @@ METHOD(hasher_t, get_hash_size, size_t, return this->size; } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_af_alg_hasher_t *this) { this->ops->reset(this->ops); + return TRUE; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_af_alg_hasher_t *this, chunk_t chunk, u_int8_t *hash) { - this->ops->hash(this->ops, chunk, hash, this->size); + return this->ops->hash(this->ops, chunk, hash, this->size); } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_af_alg_hasher_t *this, chunk_t chunk, chunk_t *hash) { if (hash) { *hash = chunk_alloc(get_hash_size(this)); - get_hash(this, chunk, hash->ptr); - } - else - { - get_hash(this, chunk, NULL); + return get_hash(this, chunk, hash->ptr); } + return get_hash(this, chunk, NULL); } METHOD(hasher_t, destroy, void, diff --git a/src/libstrongswan/plugins/af_alg/af_alg_ops.c b/src/libstrongswan/plugins/af_alg/af_alg_ops.c index a7b5de264..7fe47c578 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_ops.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_ops.c @@ -54,7 +54,7 @@ METHOD(af_alg_ops_t, reset, void, } } -METHOD(af_alg_ops_t, hash, void, +METHOD(af_alg_ops_t, hash, bool, private_af_alg_ops_t *this, chunk_t data, char *out, size_t outlen) { ssize_t len; @@ -62,39 +62,52 @@ METHOD(af_alg_ops_t, hash, void, while (this->op == -1) { this->op = accept(this->tfm, NULL, 0); - if (this->op == -1) + if (this->op == -1 && errno != EINTR) { DBG1(DBG_LIB, "opening AF_ALG hasher failed: %s", strerror(errno)); - sleep(1); + return FALSE; } } + do { len = send(this->op, data.ptr, data.len, out ? 0 : MSG_MORE); if (len == -1) { + if (errno == EINTR) + { + continue; + } DBG1(DBG_LIB, "writing to AF_ALG hasher failed: %s", strerror(errno)); - sleep(1); - } - else - { - data = chunk_skip(data, len); + return FALSE; } + data = chunk_skip(data, len); } while (data.len); if (out) { - while (read(this->op, out, outlen) != outlen) + while (outlen) { - DBG1(DBG_LIB, "reading AF_ALG hasher failed: %s", strerror(errno)); - sleep(1); + len = read(this->op, out, outlen); + if (len == -1) + { + if (errno == EINTR) + { + continue; + } + DBG1(DBG_LIB, "reading AF_ALG hasher failed: %s", strerror(errno)); + return FALSE; + } + outlen -= len; + out += len; } reset(this); } + return TRUE; } -METHOD(af_alg_ops_t, crypt, void, +METHOD(af_alg_ops_t, crypt, bool, private_af_alg_ops_t *this, u_int32_t type, chunk_t iv, chunk_t data, char *out) { @@ -107,11 +120,16 @@ METHOD(af_alg_ops_t, crypt, void, ssize_t len; int op; - while ((op = accept(this->tfm, NULL, 0)) == -1) + do { - DBG1(DBG_LIB, "accepting AF_ALG crypter failed: %s", strerror(errno)); - sleep(1); + op = accept(this->tfm, NULL, 0); + if (op == -1 && errno != EINTR) + { + DBG1(DBG_LIB, "accepting AF_ALG crypter failed: %s", strerror(errno)); + return FALSE; + } } + while (op == -1); memset(buf, 0, sizeof(buf)); @@ -143,30 +161,39 @@ METHOD(af_alg_ops_t, crypt, void, len = sendmsg(op, &msg, 0); if (len == -1) { - DBG1(DBG_LIB, "writing to AF_ALG crypter failed: %s", - strerror(errno)); - sleep(1); - continue; + if (errno == EINTR) + { + continue; + } + DBG1(DBG_LIB, "writing to AF_ALG crypter failed: %s", strerror(errno)); + return FALSE; } - if (read(op, out, len) != len) + while (read(op, out, len) != len) { - DBG1(DBG_LIB, "reading from AF_ALG crypter failed: %s", - strerror(errno)); + if (errno != EINTR) + { + DBG1(DBG_LIB, "reading from AF_ALG crypter failed: %s", + strerror(errno)); + return FALSE; + } } data = chunk_skip(data, len); /* no IV for subsequent data chunks */ msg.msg_controllen = 0; } close(op); + return TRUE; } -METHOD(af_alg_ops_t, set_key, void, +METHOD(af_alg_ops_t, set_key, bool, private_af_alg_ops_t *this, chunk_t key) { if (setsockopt(this->tfm, SOL_ALG, ALG_SET_KEY, key.ptr, key.len) == -1) { DBG1(DBG_LIB, "setting AF_ALG key failed: %s", strerror(errno)); + return FALSE; } + return TRUE; } METHOD(af_alg_ops_t, destroy, void, diff --git a/src/libstrongswan/plugins/af_alg/af_alg_ops.h b/src/libstrongswan/plugins/af_alg/af_alg_ops.h index ad164029f..e34f22977 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_ops.h +++ b/src/libstrongswan/plugins/af_alg/af_alg_ops.h @@ -46,8 +46,9 @@ struct af_alg_ops_t { * @param data data to hash * @param out buffer to write hash to, NULL for append mode * @param outlen number of bytes to read into out + * @return TRUE if successful */ - void (*hash)(af_alg_ops_t *this, chunk_t data, char *out, size_t outlen); + bool (*hash)(af_alg_ops_t *this, chunk_t data, char *out, size_t outlen); /** * Reset hasher state. @@ -61,16 +62,18 @@ struct af_alg_ops_t { * @param iv iv to use * @param data data to encrypt/decrypt * @param out buffer write processed data to + * @return TRUE if successful */ - void (*crypt)(af_alg_ops_t *this, u_int32_t type, chunk_t iv, chunk_t data, + bool (*crypt)(af_alg_ops_t *this, u_int32_t type, chunk_t iv, chunk_t data, char *out); /** * Set the key for en-/decryption or HMAC/XCBC operations. * * @param key key to set for transform + * @return TRUE if successful */ - void (*set_key)(af_alg_ops_t *this, chunk_t key); + bool (*set_key)(af_alg_ops_t *this, chunk_t key); /** * Destroy a af_alg_ops_t. diff --git a/src/libstrongswan/plugins/af_alg/af_alg_prf.c b/src/libstrongswan/plugins/af_alg/af_alg_prf.c index a7912291f..720738a84 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_prf.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_prf.c @@ -105,24 +105,21 @@ static size_t lookup_alg(pseudo_random_function_t algo, char **name, bool *xcbc) return 0; } -METHOD(prf_t, get_bytes, void, +METHOD(prf_t, get_bytes, bool, private_af_alg_prf_t *this, chunk_t seed, u_int8_t *buffer) { - this->ops->hash(this->ops, seed, buffer, this->block_size); + return this->ops->hash(this->ops, seed, buffer, this->block_size); } -METHOD(prf_t, allocate_bytes, void, +METHOD(prf_t, allocate_bytes, bool, private_af_alg_prf_t *this, chunk_t seed, chunk_t *chunk) { if (chunk) { *chunk = chunk_alloc(this->block_size); - get_bytes(this, seed, chunk->ptr); - } - else - { - get_bytes(this, seed, NULL); + return get_bytes(this, seed, chunk->ptr); } + return get_bytes(this, seed, NULL); } METHOD(prf_t, get_block_size, size_t, @@ -137,7 +134,7 @@ METHOD(prf_t, get_key_size, size_t, return this->block_size; } -METHOD(prf_t, set_key, void, +METHOD(prf_t, set_key, bool, private_af_alg_prf_t *this, chunk_t key) { char buf[this->block_size]; @@ -155,12 +152,15 @@ METHOD(prf_t, set_key, void, else if (key.len > this->block_size) { memset(buf, 0, this->block_size); - this->ops->set_key(this->ops, chunk_from_thing(buf)); - this->ops->hash(this->ops, key, buf, this->block_size); + if (!this->ops->set_key(this->ops, chunk_from_thing(buf)) || + !this->ops->hash(this->ops, key, buf, this->block_size)) + { + return FALSE; + } key = chunk_from_thing(buf); } } - this->ops->set_key(this->ops, key); + return this->ops->set_key(this->ops, key); } METHOD(prf_t, destroy, void, diff --git a/src/libstrongswan/plugins/af_alg/af_alg_signer.c b/src/libstrongswan/plugins/af_alg/af_alg_signer.c index 6cd79f8f2..d995b1351 100644 --- a/src/libstrongswan/plugins/af_alg/af_alg_signer.c +++ b/src/libstrongswan/plugins/af_alg/af_alg_signer.c @@ -107,24 +107,21 @@ static size_t lookup_alg(integrity_algorithm_t algo, char **name, return 0; } -METHOD(signer_t, get_signature, void, +METHOD(signer_t, get_signature, bool, private_af_alg_signer_t *this, chunk_t data, u_int8_t *buffer) { - this->ops->hash(this->ops, data, buffer, this->block_size); + return this->ops->hash(this->ops, data, buffer, this->block_size); } -METHOD(signer_t, allocate_signature, void, +METHOD(signer_t, allocate_signature, bool, private_af_alg_signer_t *this, chunk_t data, chunk_t *chunk) { if (chunk) { *chunk = chunk_alloc(this->block_size); - get_signature(this, data, chunk->ptr); - } - else - { - get_signature(this, data, NULL); + return get_signature(this, data, chunk->ptr); } + return get_signature(this, data, NULL); } METHOD(signer_t, verify_signature, bool, @@ -136,7 +133,10 @@ METHOD(signer_t, verify_signature, bool, { return FALSE; } - get_signature(this, data, sig); + if (!get_signature(this, data, sig)) + { + return FALSE; + } return memeq(signature.ptr, sig, signature.len); } @@ -152,10 +152,10 @@ METHOD(signer_t, get_block_size, size_t, return this->block_size; } -METHOD(signer_t, set_key, void, +METHOD(signer_t, set_key, bool, private_af_alg_signer_t *this, chunk_t key) { - this->ops->set_key(this->ops, key); + return this->ops->set_key(this->ops, key); } METHOD(signer_t, destroy, void, diff --git a/src/libstrongswan/plugins/agent/Makefile.in b/src/libstrongswan/plugins/agent/Makefile.in index 452233b85..8e606bf39 100644 --- a/src/libstrongswan/plugins/agent/Makefile.in +++ b/src/libstrongswan/plugins/agent/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_agent_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_agent_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_agent_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/blowfish/Makefile.in b/src/libstrongswan/plugins/blowfish/Makefile.in index 52f5fa98a..c8b904eb9 100644 --- a/src/libstrongswan/plugins/blowfish/Makefile.in +++ b/src/libstrongswan/plugins/blowfish/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_blowfish_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_blowfish_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_blowfish_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/blowfish/blowfish_crypter.c b/src/libstrongswan/plugins/blowfish/blowfish_crypter.c index fc3649b36..253f9b4a4 100644 --- a/src/libstrongswan/plugins/blowfish/blowfish_crypter.c +++ b/src/libstrongswan/plugins/blowfish/blowfish_crypter.c @@ -87,7 +87,7 @@ struct private_blowfish_crypter_t { u_int32_t key_size; }; -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_blowfish_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) { @@ -108,9 +108,11 @@ METHOD(crypter_t, decrypt, void, BF_cbc_encrypt(in, out, data.len, &this->schedule, iv.ptr, 0); free(iv.ptr); + + return TRUE; } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_blowfish_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) { @@ -131,6 +133,8 @@ METHOD(crypter_t, encrypt, void, BF_cbc_encrypt(in, out, data.len, &this->schedule, iv.ptr, 1); free(iv.ptr); + + return TRUE; } METHOD(crypter_t, get_block_size, size_t, @@ -151,10 +155,11 @@ METHOD(crypter_t, get_key_size, size_t, return this->key_size; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_blowfish_crypter_t *this, chunk_t key) { BF_set_key(&this->schedule, key.len , key.ptr); + return TRUE; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/ccm/Makefile.in b/src/libstrongswan/plugins/ccm/Makefile.in index 2ffe6194b..bb094f04c 100644 --- a/src/libstrongswan/plugins/ccm/Makefile.in +++ b/src/libstrongswan/plugins/ccm/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_ccm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_ccm_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_ccm_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_ccm_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/ccm/ccm_aead.c b/src/libstrongswan/plugins/ccm/ccm_aead.c index 0d2a56a49..0e2f9b75f 100644 --- a/src/libstrongswan/plugins/ccm/ccm_aead.c +++ b/src/libstrongswan/plugins/ccm/ccm_aead.c @@ -126,7 +126,7 @@ static void build_ctr(private_ccm_aead_t *this, u_int32_t i, chunk_t iv, /** * En-/Decrypt data */ -static void crypt_data(private_ccm_aead_t *this, chunk_t iv, +static bool crypt_data(private_ccm_aead_t *this, chunk_t iv, chunk_t in, chunk_t out) { char ctr[BLOCK_SIZE]; @@ -139,8 +139,11 @@ static void crypt_data(private_ccm_aead_t *this, chunk_t iv, while (in.len > 0) { memcpy(block, ctr, BLOCK_SIZE); - this->crypter->encrypt(this->crypter, chunk_from_thing(block), - chunk_from_thing(zero), NULL); + if (!this->crypter->encrypt(this->crypter, chunk_from_thing(block), + chunk_from_thing(zero), NULL)) + { + return FALSE; + } chunk_increment(chunk_from_thing(ctr)); if (in.ptr != out.ptr) @@ -151,12 +154,13 @@ static void crypt_data(private_ccm_aead_t *this, chunk_t iv, in = chunk_skip(in, BLOCK_SIZE); out = chunk_skip(out, BLOCK_SIZE); } + return TRUE; } /** * En-/Decrypt the ICV */ -static void crypt_icv(private_ccm_aead_t *this, chunk_t iv, char *icv) +static bool crypt_icv(private_ccm_aead_t *this, chunk_t iv, char *icv) { char ctr[BLOCK_SIZE]; char zero[BLOCK_SIZE]; @@ -164,15 +168,19 @@ static void crypt_icv(private_ccm_aead_t *this, chunk_t iv, char *icv) build_ctr(this, 0, iv, ctr); memset(zero, 0, BLOCK_SIZE); - this->crypter->encrypt(this->crypter, chunk_from_thing(ctr), - chunk_from_thing(zero), NULL); + if (!this->crypter->encrypt(this->crypter, chunk_from_thing(ctr), + chunk_from_thing(zero), NULL)) + { + return FALSE; + } memxor(icv, ctr, this->icv_size); + return TRUE; } /** * Create the ICV */ -static void create_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, +static bool create_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, char *icv) { char zero[BLOCK_SIZE]; @@ -217,14 +225,19 @@ static void create_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, memset(pos, 0, len); /* encrypt inline with CBC, zero IV */ - this->crypter->encrypt(this->crypter, chunk, chunk_from_thing(zero), NULL); + if (!this->crypter->encrypt(this->crypter, chunk, + chunk_from_thing(zero), NULL)) + { + free(chunk.ptr); + return FALSE; + } /* copy last icv_size bytes as ICV to output */ memcpy(icv, chunk.ptr + chunk.len - BLOCK_SIZE, this->icv_size); - /* encrypt the ICV value */ - crypt_icv(this, iv, icv); - free(chunk.ptr); + + /* encrypt the ICV value */ + return crypt_icv(this, iv, icv); } /** @@ -235,26 +248,22 @@ static bool verify_icv(private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, { char buf[this->icv_size]; - create_icv(this, plain, assoc, iv, buf); - - return memeq(buf, icv, this->icv_size); + return create_icv(this, plain, assoc, iv, buf) && + memeq(buf, icv, this->icv_size); } -METHOD(aead_t, encrypt, void, +METHOD(aead_t, encrypt, bool, private_ccm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, chunk_t *encrypted) { if (encrypted) { *encrypted = chunk_alloc(plain.len + this->icv_size); - create_icv(this, plain, assoc, iv, encrypted->ptr + plain.len); - crypt_data(this, iv, plain, *encrypted); - } - else - { - create_icv(this, plain, assoc, iv, plain.ptr + plain.len); - crypt_data(this, iv, plain, plain); + return create_icv(this, plain, assoc, iv, encrypted->ptr + plain.len) && + crypt_data(this, iv, plain, *encrypted); } + return create_icv(this, plain, assoc, iv, plain.ptr + plain.len) && + crypt_data(this, iv, plain, plain); } METHOD(aead_t, decrypt, bool, @@ -269,16 +278,13 @@ METHOD(aead_t, decrypt, bool, if (plain) { *plain = chunk_alloc(encrypted.len); - crypt_data(this, iv, encrypted, *plain); - return verify_icv(this, *plain, assoc, iv, - encrypted.ptr + encrypted.len); - } - else - { - crypt_data(this, iv, encrypted, encrypted); - return verify_icv(this, encrypted, assoc, iv, + return crypt_data(this, iv, encrypted, *plain) && + verify_icv(this, *plain, assoc, iv, encrypted.ptr + encrypted.len); } + return crypt_data(this, iv, encrypted, encrypted) && + verify_icv(this, encrypted, assoc, iv, + encrypted.ptr + encrypted.len); } METHOD(aead_t, get_block_size, size_t, @@ -305,12 +311,12 @@ METHOD(aead_t, get_key_size, size_t, return this->crypter->get_key_size(this->crypter) + SALT_SIZE; } -METHOD(aead_t, set_key, void, +METHOD(aead_t, set_key, bool, private_ccm_aead_t *this, chunk_t key) { memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE); key.len -= SALT_SIZE; - this->crypter->set_key(this->crypter, key); + return this->crypter->set_key(this->crypter, key); } METHOD(aead_t, destroy, void, diff --git a/src/libstrongswan/plugins/cmac/Makefile.am b/src/libstrongswan/plugins/cmac/Makefile.am index ce0104f11..5cac3959c 100644 --- a/src/libstrongswan/plugins/cmac/Makefile.am +++ b/src/libstrongswan/plugins/cmac/Makefile.am @@ -10,7 +10,6 @@ plugin_LTLIBRARIES = libstrongswan-cmac.la endif libstrongswan_cmac_la_SOURCES = \ - cmac_plugin.h cmac_plugin.c cmac.h cmac.c \ - cmac_prf.h cmac_prf.c cmac_signer.h cmac_signer.c + cmac_plugin.h cmac_plugin.c cmac.h cmac.c libstrongswan_cmac_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/cmac/Makefile.in b/src/libstrongswan/plugins/cmac/Makefile.in index 093e63f32..eba059a29 100644 --- a/src/libstrongswan/plugins/cmac/Makefile.in +++ b/src/libstrongswan/plugins/cmac/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -75,15 +76,14 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_cmac_la_LIBADD = -am_libstrongswan_cmac_la_OBJECTS = cmac_plugin.lo cmac.lo cmac_prf.lo \ - cmac_signer.lo +am_libstrongswan_cmac_la_OBJECTS = cmac_plugin.lo cmac.lo libstrongswan_cmac_la_OBJECTS = $(am_libstrongswan_cmac_la_OBJECTS) libstrongswan_cmac_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libstrongswan_cmac_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_cmac_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_cmac_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -286,8 +291,7 @@ AM_CFLAGS = -rdynamic @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-cmac.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-cmac.la libstrongswan_cmac_la_SOURCES = \ - cmac_plugin.h cmac_plugin.c cmac.h cmac.c \ - cmac_prf.h cmac_prf.c cmac_signer.h cmac_signer.c + cmac_plugin.h cmac_plugin.c cmac.h cmac.c libstrongswan_cmac_la_LDFLAGS = -module -avoid-version all: all-am @@ -375,8 +379,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmac_plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmac_prf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmac_signer.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/libstrongswan/plugins/cmac/cmac.c b/src/libstrongswan/plugins/cmac/cmac.c index 5ec7073c7..725d02d76 100644 --- a/src/libstrongswan/plugins/cmac/cmac.c +++ b/src/libstrongswan/plugins/cmac/cmac.c @@ -18,20 +18,23 @@ #include "cmac.h" #include +#include +#include +#include -typedef struct private_cmac_t private_cmac_t; +typedef struct private_mac_t private_mac_t; /** - * Private data of a cmac_t object. + * Private data of a mac_t object. * * The variable names are the same as in the RFC. */ -struct private_cmac_t { +struct private_mac_t { /** * Public interface. */ - cmac_t public; + mac_t public; /** * Block size, in bytes @@ -72,7 +75,7 @@ struct private_cmac_t { /** * process supplied data, but do not run final operation */ -static void update(private_cmac_t *this, chunk_t data) +static bool update(private_mac_t *this, chunk_t data) { chunk_t iv; @@ -80,7 +83,7 @@ static void update(private_cmac_t *this, chunk_t data) { /* no complete block (or last block), just copy into remaining */ memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len); this->remaining_bytes += data.len; - return; + return TRUE; } iv = chunk_alloca(this->b); @@ -97,7 +100,10 @@ static void update(private_cmac_t *this, chunk_t data) this->b - this->remaining_bytes); data = chunk_skip(data, this->b - this->remaining_bytes); memxor(this->t, this->remaining, this->b); - this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL); + if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) + { + return FALSE; + } /* process blocks M_2 ... M_n-1 */ while (data.len > this->b) @@ -105,18 +111,23 @@ static void update(private_cmac_t *this, chunk_t data) memcpy(this->remaining, data.ptr, this->b); data = chunk_skip(data, this->b); memxor(this->t, this->remaining, this->b); - this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL); + if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) + { + return FALSE; + } } /* store remaining bytes of block M_n */ memcpy(this->remaining, data.ptr, data.len); this->remaining_bytes = data.len; + + return TRUE; } /** * process last block M_last */ -static void final(private_cmac_t *this, u_int8_t *out) +static bool final(private_mac_t *this, u_int8_t *out) { chunk_t iv; @@ -153,29 +164,38 @@ static void final(private_cmac_t *this, u_int8_t *out) * T := AES-128(K,T); */ memxor(this->t, this->remaining, this->b); - this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL); + if (!this->k->encrypt(this->k, chunk_create(this->t, this->b), iv, NULL)) + { + return FALSE; + } memcpy(out, this->t, this->b); /* reset state */ memset(this->t, 0, this->b); this->remaining_bytes = 0; + + return TRUE; } -METHOD(cmac_t, get_mac, void, - private_cmac_t *this, chunk_t data, u_int8_t *out) +METHOD(mac_t, get_mac, bool, + private_mac_t *this, chunk_t data, u_int8_t *out) { /* update T, do not process last block */ - update(this, data); + if (!update(this, data)) + { + return FALSE; + } if (out) { /* if not in append mode, process last block and output result */ - final(this, out); + return final(this, out); } + return TRUE; } -METHOD(cmac_t, get_block_size, size_t, - private_cmac_t *this) +METHOD(mac_t, get_mac_size, size_t, + private_mac_t *this) { return this->b; } @@ -222,8 +242,8 @@ static void derive_key(chunk_t chunk) } } -METHOD(cmac_t, set_key, void, - private_cmac_t *this, chunk_t key) +METHOD(mac_t, set_key, bool, + private_mac_t *this, chunk_t key) { chunk_t resized, iv, l; @@ -236,8 +256,11 @@ METHOD(cmac_t, set_key, void, { /* use cmac recursively to resize longer or shorter keys */ resized = chunk_alloca(this->b); memset(resized.ptr, 0, resized.len); - set_key(this, resized); - get_mac(this, key, resized.ptr); + if (!set_key(this, resized) || + !get_mac(this, key, resized.ptr)) + { + return FALSE; + } } /* @@ -256,17 +279,22 @@ METHOD(cmac_t, set_key, void, memset(iv.ptr, 0, iv.len); l = chunk_alloca(this->b); memset(l.ptr, 0, l.len); - this->k->set_key(this->k, resized); - this->k->encrypt(this->k, l, iv, NULL); + if (!this->k->set_key(this->k, resized) || + !this->k->encrypt(this->k, l, iv, NULL)) + { + return FALSE; + } derive_key(l); memcpy(this->k1, l.ptr, l.len); derive_key(l); memcpy(this->k2, l.ptr, l.len); memwipe(l.ptr, l.len); + + return TRUE; } -METHOD(cmac_t, destroy, void, - private_cmac_t *this) +METHOD(mac_t, destroy, void, + private_mac_t *this) { this->k->destroy(this->k); memwipe(this->k1, this->b); @@ -281,9 +309,9 @@ METHOD(cmac_t, destroy, void, /* * Described in header */ -cmac_t *cmac_create(encryption_algorithm_t algo, size_t key_size) +mac_t *cmac_create(encryption_algorithm_t algo, size_t key_size) { - private_cmac_t *this; + private_mac_t *this; crypter_t *crypter; u_int8_t b; @@ -303,7 +331,7 @@ cmac_t *cmac_create(encryption_algorithm_t algo, size_t key_size) INIT(this, .public = { .get_mac = _get_mac, - .get_block_size = _get_block_size, + .get_mac_size = _get_mac_size, .set_key = _set_key, .destroy = _destroy, }, @@ -319,3 +347,48 @@ cmac_t *cmac_create(encryption_algorithm_t algo, size_t key_size) return &this->public; } +/* + * Described in header. + */ +prf_t *cmac_prf_create(pseudo_random_function_t algo) +{ + mac_t *cmac; + + switch (algo) + { + case PRF_AES128_CMAC: + cmac = cmac_create(ENCR_AES_CBC, 16); + break; + default: + return NULL; + } + if (cmac) + { + return mac_prf_create(cmac); + } + return NULL; +} + +/* + * Described in header + */ +signer_t *cmac_signer_create(integrity_algorithm_t algo) +{ + size_t truncation; + mac_t *cmac; + + switch (algo) + { + case AUTH_AES_CMAC_96: + cmac = cmac_create(ENCR_AES_CBC, 16); + truncation = 12; + break; + default: + return NULL; + } + if (cmac) + { + return mac_signer_create(cmac, truncation); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/cmac/cmac.h b/src/libstrongswan/plugins/cmac/cmac.h index 061609127..dc85e3bc3 100644 --- a/src/libstrongswan/plugins/cmac/cmac.h +++ b/src/libstrongswan/plugins/cmac/cmac.h @@ -14,6 +14,11 @@ */ /** + * Cipher-based Message Authentication Code (CMAC). + * + * This class implements the message authentication algorithm + * described in RFC 4493. + * * @defgroup cmac cmac * @{ @ingroup cmac_p */ @@ -21,58 +26,23 @@ #ifndef CMAC_H_ #define CMAC_H_ -#include - -typedef struct cmac_t cmac_t; +#include +#include /** - * Cipher-based Message Authentication Code (CMAC). + * Creates a new prf_t object based on a CMAC. * - * This class implements the message authentication algorithm - * described in RFC 4493. + * @param algo algorithm to implement + * @return prf_t object, NULL if not supported */ -struct cmac_t { - - /** - * Generate message authentication code. - * - * If buffer is NULL, no result is given back. A next call will - * append the data to already supplied data. If buffer is not NULL, - * the mac of all apended data is calculated, returned and the internal - * state is reset. - * - * @param data chunk of data to authenticate - * @param buffer pointer where the generated bytes will be written - */ - void (*get_mac) (cmac_t *this, chunk_t data, u_int8_t *buffer); - - /** - * Get the block size of this cmac_t object. - * - * @return block size in bytes - */ - size_t (*get_block_size) (cmac_t *this); - - /** - * Set the key for this cmac_t object. - * - * @param key key to set - */ - void (*set_key) (cmac_t *this, chunk_t key); - - /** - * Destroys a cmac_t object. - */ - void (*destroy) (cmac_t *this); -}; +prf_t *cmac_prf_create(pseudo_random_function_t algo); /** - * Creates a new cmac_t object. + * Creates a new signer_t object based on a CMAC. * - * @param algo underlying crypto algorithm - * @param key_size key size to use, if required for algorithm - * @return cmac_t object, NULL if not supported + * @param algo algorithm to implement + * @return signer_t, NULL if not supported */ -cmac_t *cmac_create(encryption_algorithm_t algo, size_t key_size); +signer_t *cmac_signer_create(integrity_algorithm_t algo); #endif /** CMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/cmac/cmac_plugin.c b/src/libstrongswan/plugins/cmac/cmac_plugin.c index 5b42c5002..694e598a5 100644 --- a/src/libstrongswan/plugins/cmac/cmac_plugin.c +++ b/src/libstrongswan/plugins/cmac/cmac_plugin.c @@ -16,8 +16,7 @@ #include "cmac_plugin.h" #include -#include "cmac_prf.h" -#include "cmac_signer.h" +#include "cmac.h" typedef struct private_cmac_plugin_t private_cmac_plugin_t; diff --git a/src/libstrongswan/plugins/cmac/cmac_prf.c b/src/libstrongswan/plugins/cmac/cmac_prf.c deleted file mode 100644 index 17affe439..000000000 --- a/src/libstrongswan/plugins/cmac/cmac_prf.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "cmac_prf.h" - -#include "cmac.h" - -typedef struct private_cmac_prf_t private_cmac_prf_t; - -/** - * Private data of a cmac_prf_t object. - */ -struct private_cmac_prf_t { - - /** - * Public cmac_prf_t interface. - */ - cmac_prf_t public; - - /** - * cmac to use for generation. - */ - cmac_t *cmac; -}; - -METHOD(prf_t, get_bytes, void, - private_cmac_prf_t *this, chunk_t seed, u_int8_t *buffer) -{ - this->cmac->get_mac(this->cmac, seed, buffer); -} - -METHOD(prf_t, allocate_bytes, void, - private_cmac_prf_t *this, chunk_t seed, chunk_t *chunk) -{ - if (chunk) - { - *chunk = chunk_alloc(this->cmac->get_block_size(this->cmac)); - get_bytes(this, seed, chunk->ptr); - } - else - { - get_bytes(this, seed, NULL); - } -} - -METHOD(prf_t, get_block_size, size_t, - private_cmac_prf_t *this) -{ - return this->cmac->get_block_size(this->cmac); -} - -METHOD(prf_t, get_key_size, size_t, - private_cmac_prf_t *this) -{ - /* in cmac, block and key size are always equal */ - return this->cmac->get_block_size(this->cmac); -} - -METHOD(prf_t, set_key, void, - private_cmac_prf_t *this, chunk_t key) -{ - this->cmac->set_key(this->cmac, key); -} - -METHOD(prf_t, destroy, void, - private_cmac_prf_t *this) -{ - this->cmac->destroy(this->cmac); - free(this); -} - -/* - * Described in header. - */ -cmac_prf_t *cmac_prf_create(pseudo_random_function_t algo) -{ - private_cmac_prf_t *this; - cmac_t *cmac; - - switch (algo) - { - case PRF_AES128_CMAC: - cmac = cmac_create(ENCR_AES_CBC, 16); - break; - default: - return NULL; - } - if (!cmac) - { - return NULL; - } - - INIT(this, - .public = { - .prf = { - .get_bytes = _get_bytes, - .allocate_bytes = _allocate_bytes, - .get_block_size = _get_block_size, - .get_key_size = _get_key_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .cmac = cmac, - ); - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/cmac/cmac_prf.h b/src/libstrongswan/plugins/cmac/cmac_prf.h deleted file mode 100644 index a53cc5947..000000000 --- a/src/libstrongswan/plugins/cmac/cmac_prf.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup cmac_prf cmac_prf - * @{ @ingroup cmac_p - */ - -#ifndef PRF_CMAC_H_ -#define PRF_CMAC_H_ - -typedef struct cmac_prf_t cmac_prf_t; - -#include - -/** - * Implementation of prf_t on CBC block cipher using CMAC, RFC 4493 / RFC 4615. - * - * This simply wraps a cmac_t in a prf_t. More a question of - * interface matching. - */ -struct cmac_prf_t { - - /** - * Implements prf_t interface. - */ - prf_t prf; -}; - -/** - * Creates a new cmac_prf_t object. - * - * @param algo algorithm to implement - * @return cmac_prf_t object, NULL if hash not supported - */ -cmac_prf_t *cmac_prf_create(pseudo_random_function_t algo); - -#endif /** PRF_CMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/cmac/cmac_signer.c b/src/libstrongswan/plugins/cmac/cmac_signer.c deleted file mode 100644 index 82e8885d6..000000000 --- a/src/libstrongswan/plugins/cmac/cmac_signer.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "cmac_signer.h" -#include "cmac.h" - -typedef struct private_cmac_signer_t private_cmac_signer_t; - -/** - * Private data structure with signing context. - */ -struct private_cmac_signer_t { - - /** - * Public interface. - */ - cmac_signer_t public; - - /** - * Assigned cmac function. - */ - cmac_t *cmac; - - /** - * Block size (truncation of CMAC MAC) - */ - size_t block_size; -}; - -METHOD(signer_t, get_signature, void, - private_cmac_signer_t *this, chunk_t data, u_int8_t *buffer) -{ - if (buffer == NULL) - { /* append mode */ - this->cmac->get_mac(this->cmac, data, NULL); - } - else - { - u_int8_t mac[this->cmac->get_block_size(this->cmac)]; - - this->cmac->get_mac(this->cmac, data, mac); - memcpy(buffer, mac, this->block_size); - } -} - -METHOD(signer_t, allocate_signature, void, - private_cmac_signer_t *this, chunk_t data, chunk_t *chunk) -{ - if (chunk == NULL) - { /* append mode */ - this->cmac->get_mac(this->cmac, data, NULL); - } - else - { - u_int8_t mac[this->cmac->get_block_size(this->cmac)]; - - this->cmac->get_mac(this->cmac, data, mac); - - chunk->ptr = malloc(this->block_size); - chunk->len = this->block_size; - - memcpy(chunk->ptr, mac, this->block_size); - } -} - -METHOD(signer_t, verify_signature, bool, - private_cmac_signer_t *this, chunk_t data, chunk_t signature) -{ - u_int8_t mac[this->cmac->get_block_size(this->cmac)]; - - if (signature.len != this->block_size) - { - return FALSE; - } - - this->cmac->get_mac(this->cmac, data, mac); - return memeq(signature.ptr, mac, this->block_size); -} - -METHOD(signer_t, get_key_size, size_t, - private_cmac_signer_t *this) -{ - return this->cmac->get_block_size(this->cmac); -} - -METHOD(signer_t, get_block_size, size_t, - private_cmac_signer_t *this) -{ - return this->block_size; -} - -METHOD(signer_t, set_key, void, - private_cmac_signer_t *this, chunk_t key) -{ - this->cmac->set_key(this->cmac, key); -} - -METHOD(signer_t, destroy, void, - private_cmac_signer_t *this) -{ - this->cmac->destroy(this->cmac); - free(this); -} - -/* - * Described in header - */ -cmac_signer_t *cmac_signer_create(integrity_algorithm_t algo) -{ - private_cmac_signer_t *this; - size_t truncation; - cmac_t *cmac; - - switch (algo) - { - case AUTH_AES_CMAC_96: - cmac = cmac_create(ENCR_AES_CBC, 16); - truncation = 12; - break; - default: - return NULL; - } - if (cmac == NULL) - { - return NULL; - } - - INIT(this, - .public = { - .signer = { - .get_signature = _get_signature, - .allocate_signature = _allocate_signature, - .verify_signature = _verify_signature, - .get_key_size = _get_key_size, - .get_block_size = _get_block_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .cmac = cmac, - .block_size = min(truncation, cmac->get_block_size(cmac)), - ); - - return &this->public; -} diff --git a/src/libstrongswan/plugins/cmac/cmac_signer.h b/src/libstrongswan/plugins/cmac/cmac_signer.h deleted file mode 100644 index 2e3724471..000000000 --- a/src/libstrongswan/plugins/cmac/cmac_signer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup cmac_signer cmac_signer - * @{ @ingroup cmac_p - */ - -#ifndef CMAC_SIGNER_H_ -#define CMAC_SIGNER_H_ - -typedef struct cmac_signer_t cmac_signer_t; - -#include - -/** - * Implementation of signer_t on CBC symmetric cipher using CMAC, RFC 4494. - */ -struct cmac_signer_t { - - /** - * Implements signer_t interface. - */ - signer_t signer; -}; - -/** - * Creates a new cmac_signer_t. - * - * @param algo algorithm to implement - * @return cmac_signer_t, NULL if not supported - */ -cmac_signer_t *cmac_signer_create(integrity_algorithm_t algo); - -#endif /** CMAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/plugins/constraints/Makefile.in b/src/libstrongswan/plugins/constraints/Makefile.in index 06b66db60..693d76334 100644 --- a/src/libstrongswan/plugins/constraints/Makefile.in +++ b/src/libstrongswan/plugins/constraints/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_constraints_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_constraints_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_constraints_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/ctr/Makefile.in b/src/libstrongswan/plugins/ctr/Makefile.in index 853625a19..adab5d7d5 100644 --- a/src/libstrongswan/plugins/ctr/Makefile.in +++ b/src/libstrongswan/plugins/ctr/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_ctr_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_ctr_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_ctr_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_ctr_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/ctr/ctr_ipsec_crypter.c b/src/libstrongswan/plugins/ctr/ctr_ipsec_crypter.c index ddcae423b..59d201a6f 100644 --- a/src/libstrongswan/plugins/ctr/ctr_ipsec_crypter.c +++ b/src/libstrongswan/plugins/ctr/ctr_ipsec_crypter.c @@ -45,7 +45,7 @@ struct private_ctr_ipsec_crypter_t { /** * Do the CTR crypto operation */ -static void crypt_ctr(private_ctr_ipsec_crypter_t *this, +static bool crypt_ctr(private_ctr_ipsec_crypter_t *this, chunk_t in, chunk_t out) { size_t is, bs; @@ -63,8 +63,11 @@ static void crypt_ctr(private_ctr_ipsec_crypter_t *this, memset(iv, 0, is); memcpy(block, state.ptr, bs); - this->crypter->encrypt(this->crypter, - chunk_create(block, bs), chunk_create(iv, is), NULL); + if (!this->crypter->encrypt(this->crypter, chunk_create(block, bs), + chunk_create(iv, is), NULL)) + { + return FALSE; + } chunk_increment(state); if (in.ptr != out.ptr) @@ -75,9 +78,10 @@ static void crypt_ctr(private_ctr_ipsec_crypter_t *this, in = chunk_skip(in, bs); out = chunk_skip(out, bs); } + return TRUE; } -METHOD(crypter_t, crypt, void, +METHOD(crypter_t, crypt, bool, private_ctr_ipsec_crypter_t *this, chunk_t in, chunk_t iv, chunk_t *out) { memcpy(this->state.iv, iv.ptr, sizeof(this->state.iv)); @@ -85,12 +89,9 @@ METHOD(crypter_t, crypt, void, if (out) { *out = chunk_alloc(in.len); - crypt_ctr(this, in, *out); - } - else - { - crypt_ctr(this, in, in); + return crypt_ctr(this, in, *out); } + return crypt_ctr(this, in, in); } METHOD(crypter_t, get_block_size, size_t, @@ -112,13 +113,13 @@ METHOD(crypter_t, get_key_size, size_t, + sizeof(this->state.nonce); } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_ctr_ipsec_crypter_t *this, chunk_t key) { memcpy(this->state.nonce, key.ptr + key.len - sizeof(this->state.nonce), sizeof(this->state.nonce)); key.len -= sizeof(this->state.nonce); - this->crypter->set_key(this->crypter, key); + return this->crypter->set_key(this->crypter, key); } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/curl/Makefile.in b/src/libstrongswan/plugins/curl/Makefile.in index 5b83c60f8..b6f38681f 100644 --- a/src/libstrongswan/plugins/curl/Makefile.in +++ b/src/libstrongswan/plugins/curl/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_curl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_curl_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_curl_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_curl_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/des/Makefile.in b/src/libstrongswan/plugins/des/Makefile.in index f4056951a..04d489824 100644 --- a/src/libstrongswan/plugins/des/Makefile.in +++ b/src/libstrongswan/plugins/des/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_des_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_des_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_des_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_des_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/des/des_crypter.c b/src/libstrongswan/plugins/des/des_crypter.c index bc399ef8a..c81318b19 100644 --- a/src/libstrongswan/plugins/des/des_crypter.c +++ b/src/libstrongswan/plugins/des/des_crypter.c @@ -1416,7 +1416,7 @@ static void des_ede3_cbc_encrypt(des_cblock *input, des_cblock *output, long len tin[0]=tin[1]=0; } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) { des_cblock ivb; @@ -1431,10 +1431,11 @@ METHOD(crypter_t, decrypt, void, memcpy(&ivb, iv.ptr, sizeof(des_cblock)); des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks, &ivb, DES_DECRYPT); + return TRUE; } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) { des_cblock ivb; @@ -1449,9 +1450,10 @@ METHOD(crypter_t, encrypt, void, memcpy(&ivb, iv.ptr, sizeof(des_cblock)); des_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks, &ivb, DES_ENCRYPT); + return TRUE; } -METHOD(crypter_t, decrypt_ecb, void, +METHOD(crypter_t, decrypt_ecb, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) { u_int8_t *out; @@ -1464,9 +1466,10 @@ METHOD(crypter_t, decrypt_ecb, void, } des_ecb_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks, DES_DECRYPT); + return TRUE; } -METHOD(crypter_t, encrypt_ecb, void, +METHOD(crypter_t, encrypt_ecb, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) { u_int8_t *out; @@ -1479,9 +1482,10 @@ METHOD(crypter_t, encrypt_ecb, void, } des_ecb_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks, DES_ENCRYPT); + return TRUE; } -METHOD(crypter_t, decrypt3, void, +METHOD(crypter_t, decrypt3, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *decrypted) { des_cblock ivb; @@ -1497,9 +1501,10 @@ METHOD(crypter_t, decrypt3, void, des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks3[0], this->ks3[1], this->ks3[2], &ivb, DES_DECRYPT); + return TRUE; } -METHOD(crypter_t, encrypt3, void, +METHOD(crypter_t, encrypt3, bool, private_des_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *encrypted) { des_cblock ivb; @@ -1515,6 +1520,7 @@ METHOD(crypter_t, encrypt3, void, des_ede3_cbc_encrypt((des_cblock*)(data.ptr), (des_cblock*)out, data.len, this->ks3[0], this->ks3[1], this->ks3[2], &ivb, DES_ENCRYPT); + return TRUE; } METHOD(crypter_t, get_block_size, size_t, @@ -1535,18 +1541,20 @@ METHOD(crypter_t, get_key_size, size_t, return this->key_size; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_des_crypter_t *this, chunk_t key) { des_set_key((des_cblock*)(key.ptr), &this->ks); + return TRUE; } -METHOD(crypter_t, set_key3, void, +METHOD(crypter_t, set_key3, bool, private_des_crypter_t *this, chunk_t key) { des_set_key((des_cblock*)(key.ptr) + 0, &this->ks3[0]); des_set_key((des_cblock*)(key.ptr) + 1, &this->ks3[1]); des_set_key((des_cblock*)(key.ptr) + 2, &this->ks3[2]); + return TRUE; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/dnskey/Makefile.in b/src/libstrongswan/plugins/dnskey/Makefile.in index dabddd6d0..2f86f7558 100644 --- a/src/libstrongswan/plugins/dnskey/Makefile.in +++ b/src/libstrongswan/plugins/dnskey/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_dnskey_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_dnskey_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_dnskey_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/fips_prf/Makefile.in b/src/libstrongswan/plugins/fips_prf/Makefile.in index cbe9ef303..017f00e50 100644 --- a/src/libstrongswan/plugins/fips_prf/Makefile.in +++ b/src/libstrongswan/plugins/fips_prf/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_fips_prf_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_fips_prf_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_fips_prf_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/fips_prf/fips_prf.c b/src/libstrongswan/plugins/fips_prf/fips_prf.c index c0666367a..3fe204d35 100644 --- a/src/libstrongswan/plugins/fips_prf/fips_prf.c +++ b/src/libstrongswan/plugins/fips_prf/fips_prf.c @@ -48,7 +48,7 @@ struct private_fips_prf_t { /** * G function, either SHA1 or DES */ - void (*g)(private_fips_prf_t *this, chunk_t c, u_int8_t res[]); + bool (*g)(private_fips_prf_t *this, chunk_t c, u_int8_t res[]); }; /** @@ -106,7 +106,7 @@ static void chunk_mod(size_t length, chunk_t chunk, u_int8_t buffer[]) * 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78, * 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16 */ -METHOD(prf_t, get_bytes, void, +METHOD(prf_t, get_bytes, bool, private_fips_prf_t *this, chunk_t seed, u_int8_t w[]) { int i; @@ -138,6 +138,8 @@ METHOD(prf_t, get_bytes, void, } /* 3.3 done already, mod q not used */ + + return TRUE; } METHOD(prf_t, get_block_size, size_t, @@ -145,11 +147,11 @@ METHOD(prf_t, get_block_size, size_t, { return 2 * this->b; } -METHOD(prf_t, allocate_bytes, void, +METHOD(prf_t, allocate_bytes, bool, private_fips_prf_t *this, chunk_t seed, chunk_t *chunk) { *chunk = chunk_alloc(get_block_size(this)); - get_bytes(this, seed, chunk->ptr); + return get_bytes(this, seed, chunk->ptr); } METHOD(prf_t, get_key_size, size_t, @@ -158,17 +160,18 @@ METHOD(prf_t, get_key_size, size_t, return this->b; } -METHOD(prf_t, set_key, void, +METHOD(prf_t, set_key, bool, private_fips_prf_t *this, chunk_t key) { /* save key as "key mod 2^b" */ chunk_mod(this->b, key, this->key); + return TRUE; } /** * Implementation of the G() function based on SHA1 */ -void g_sha1(private_fips_prf_t *this, chunk_t c, u_int8_t res[]) +static bool g_sha1(private_fips_prf_t *this, chunk_t c, u_int8_t res[]) { u_int8_t buf[64]; @@ -187,8 +190,12 @@ void g_sha1(private_fips_prf_t *this, chunk_t c, u_int8_t res[]) } /* use the keyed hasher, but use an empty key to use SHA1 IV */ - this->keyed_prf->set_key(this->keyed_prf, chunk_empty); - this->keyed_prf->get_bytes(this->keyed_prf, c, res); + if (!this->keyed_prf->set_key(this->keyed_prf, chunk_empty) || + !this->keyed_prf->get_bytes(this->keyed_prf, c, res)) + { + return FALSE; + } + return TRUE; } METHOD(prf_t, destroy, void, diff --git a/src/libstrongswan/plugins/gcm/Makefile.in b/src/libstrongswan/plugins/gcm/Makefile.in index 8285b5aeb..0c5eea0a7 100644 --- a/src/libstrongswan/plugins/gcm/Makefile.in +++ b/src/libstrongswan/plugins/gcm/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_gcm_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_gcm_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_gcm_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_gcm_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/gcm/gcm_aead.c b/src/libstrongswan/plugins/gcm/gcm_aead.c index 0d7d91dbf..79ee65d98 100644 --- a/src/libstrongswan/plugins/gcm/gcm_aead.c +++ b/src/libstrongswan/plugins/gcm/gcm_aead.c @@ -149,7 +149,7 @@ static void ghash(private_gcm_aead_t *this, chunk_t x, char *res) /** * GCTR function, en-/decrypts x inline */ -static void gctr(private_gcm_aead_t *this, char *icb, chunk_t x) +static bool gctr(private_gcm_aead_t *this, char *icb, chunk_t x) { char cb[BLOCK_SIZE], iv[BLOCK_SIZE], tmp[BLOCK_SIZE]; @@ -159,12 +159,16 @@ static void gctr(private_gcm_aead_t *this, char *icb, chunk_t x) while (x.len) { memcpy(tmp, cb, BLOCK_SIZE); - this->crypter->encrypt(this->crypter, chunk_from_thing(tmp), - chunk_from_thing(iv), NULL); + if (!this->crypter->encrypt(this->crypter, chunk_from_thing(tmp), + chunk_from_thing(iv), NULL)) + { + return FALSE; + } memxor(x.ptr, tmp, min(BLOCK_SIZE, x.len)); chunk_increment(chunk_from_thing(cb)); x = chunk_skip(x, BLOCK_SIZE); } + return TRUE; } /** @@ -180,21 +184,21 @@ static void create_j(private_gcm_aead_t *this, char *iv, char *j) /** * Create GHASH subkey H */ -static void create_h(private_gcm_aead_t *this, char *h) +static bool create_h(private_gcm_aead_t *this, char *h) { char zero[BLOCK_SIZE]; memset(zero, 0, BLOCK_SIZE); memset(h, 0, BLOCK_SIZE); - this->crypter->encrypt(this->crypter, chunk_create(h, BLOCK_SIZE), - chunk_from_thing(zero), NULL); + return this->crypter->encrypt(this->crypter, chunk_create(h, BLOCK_SIZE), + chunk_from_thing(zero), NULL); } /** * Encrypt/decrypt */ -static void crypt(private_gcm_aead_t *this, char *j, chunk_t in, chunk_t out) +static bool crypt(private_gcm_aead_t *this, char *j, chunk_t in, chunk_t out) { char icb[BLOCK_SIZE]; @@ -206,13 +210,13 @@ static void crypt(private_gcm_aead_t *this, char *j, chunk_t in, chunk_t out) { memcpy(out.ptr, in.ptr, in.len); } - gctr(this, icb, out); + return gctr(this, icb, out); } /** * Create ICV */ -static void create_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt, +static bool create_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt, char *j, char *icv) { size_t assoc_pad, crypt_pad; @@ -249,9 +253,12 @@ static void create_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt, ghash(this, chunk, s); free(chunk.ptr); - gctr(this, j, chunk_from_thing(s)); - + if (!gctr(this, j, chunk_from_thing(s))) + { + return FALSE; + } memcpy(icv, s, this->icv_size); + return TRUE; } /** @@ -262,12 +269,11 @@ static bool verify_icv(private_gcm_aead_t *this, chunk_t assoc, chunk_t crypt, { char tmp[this->icv_size]; - create_icv(this, assoc, crypt, j, tmp); - - return memeq(tmp, icv, this->icv_size); + return create_icv(this, assoc, crypt, j, tmp) && + memeq(tmp, icv, this->icv_size); } -METHOD(aead_t, encrypt, void, +METHOD(aead_t, encrypt, bool, private_gcm_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, chunk_t *encrypted) { @@ -278,16 +284,13 @@ METHOD(aead_t, encrypt, void, if (encrypted) { *encrypted = chunk_alloc(plain.len + this->icv_size); - crypt(this, j, plain, *encrypted); - create_icv(this, assoc, - chunk_create(encrypted->ptr, encrypted->len - this->icv_size), - j, encrypted->ptr + encrypted->len - this->icv_size); - } - else - { - crypt(this, j, plain, plain); - create_icv(this, assoc, plain, j, plain.ptr + plain.len); + return crypt(this, j, plain, *encrypted) && + create_icv(this, assoc, + chunk_create(encrypted->ptr, encrypted->len - this->icv_size), + j, encrypted->ptr + encrypted->len - this->icv_size); } + return crypt(this, j, plain, plain) && + create_icv(this, assoc, plain, j, plain.ptr + plain.len); } METHOD(aead_t, decrypt, bool, @@ -311,13 +314,9 @@ METHOD(aead_t, decrypt, bool, if (plain) { *plain = chunk_alloc(encrypted.len); - crypt(this, j, encrypted, *plain); + return crypt(this, j, encrypted, *plain); } - else - { - crypt(this, j, encrypted, encrypted); - } - return TRUE; + return crypt(this, j, encrypted, encrypted); } METHOD(aead_t, get_block_size, size_t, @@ -344,13 +343,13 @@ METHOD(aead_t, get_key_size, size_t, return this->crypter->get_key_size(this->crypter) + SALT_SIZE; } -METHOD(aead_t, set_key, void, +METHOD(aead_t, set_key, bool, private_gcm_aead_t *this, chunk_t key) { memcpy(this->salt, key.ptr + key.len - SALT_SIZE, SALT_SIZE); key.len -= SALT_SIZE; - this->crypter->set_key(this->crypter, key); - create_h(this, this->h); + return this->crypter->set_key(this->crypter, key) && + create_h(this, this->h); } METHOD(aead_t, destroy, void, diff --git a/src/libstrongswan/plugins/gcrypt/Makefile.in b/src/libstrongswan/plugins/gcrypt/Makefile.in index 4dc72fed0..72e525b16 100644 --- a/src/libstrongswan/plugins/gcrypt/Makefile.in +++ b/src/libstrongswan/plugins/gcrypt/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_gcrypt_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_gcrypt_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_gcrypt_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c b/src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c index 599481911..0b5dc0365 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_crypter.c @@ -59,50 +59,47 @@ struct private_gcrypt_crypter_t { /** * Set the IV for en/decryption */ -static void set_iv(private_gcrypt_crypter_t *this, chunk_t iv) +static bool set_iv(private_gcrypt_crypter_t *this, chunk_t iv) { if (this->ctr_mode) { memcpy(this->ctr.iv, iv.ptr, sizeof(this->ctr.iv)); this->ctr.counter = htonl(1); - gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr)); - } - else - { - gcry_cipher_setiv(this->h, iv.ptr, iv.len); + return gcry_cipher_setctr(this->h, &this->ctr, sizeof(this->ctr)) == 0; } + return gcry_cipher_setiv(this->h, iv.ptr, iv.len) == 0; } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { - set_iv(this, iv); - - if (dst) + if (!set_iv(this, iv)) { - *dst = chunk_alloc(data.len); - gcry_cipher_decrypt(this->h, dst->ptr, dst->len, data.ptr, data.len); + return FALSE; } - else + if (dst) { - gcry_cipher_decrypt(this->h, data.ptr, data.len, NULL, 0); + *dst = chunk_alloc(data.len); + return gcry_cipher_decrypt(this->h, dst->ptr, dst->len, + data.ptr, data.len) == 0; } + return gcry_cipher_decrypt(this->h, data.ptr, data.len, NULL, 0) == 0; } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_gcrypt_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { - set_iv(this, iv); - - if (dst) + if (!set_iv(this, iv)) { - *dst = chunk_alloc(data.len); - gcry_cipher_encrypt(this->h, dst->ptr, dst->len, data.ptr, data.len); + return FALSE; } - else + if (dst) { - gcry_cipher_encrypt(this->h, data.ptr, data.len, NULL, 0); + *dst = chunk_alloc(data.len); + return gcry_cipher_encrypt(this->h, dst->ptr, dst->len, + data.ptr, data.len) == 0; } + return gcry_cipher_encrypt(this->h, data.ptr, data.len, NULL, 0) == 0; } METHOD(crypter_t, get_block_size, size_t, @@ -144,7 +141,7 @@ METHOD(crypter_t, get_key_size, size_t, return len; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_gcrypt_crypter_t *this, chunk_t key) { if (this->ctr_mode) @@ -154,7 +151,7 @@ METHOD(crypter_t, set_key, void, sizeof(this->ctr.nonce)); key.len -= sizeof(this->ctr.nonce); } - gcry_cipher_setkey(this->h, key.ptr, key.len); + return gcry_cipher_setkey(this->h, key.ptr, key.len) == 0; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c b/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c index 6c4665da2..0efd3ba16 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_dh.c @@ -208,9 +208,8 @@ gcrypt_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len, } rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (rng) + if (rng && rng->allocate_bytes(rng, exp_len, &random)) { /* prefer external randomizer */ - rng->allocate_bytes(rng, exp_len, &random); rng->destroy(rng); err = gcry_mpi_scan(&this->xa, GCRYMPI_FMT_USG, random.ptr, random.len, NULL); @@ -226,6 +225,7 @@ gcrypt_dh_t *create_generic(diffie_hellman_group_t group, size_t exp_len, } else { /* fallback to gcrypt internal randomizer, shouldn't ever happen */ + DESTROY_IF(rng); this->xa = gcry_mpi_new(exp_len * 8); gcry_mpi_randomize(this->xa, exp_len * 8, GCRY_STRONG_RANDOM); } diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_hasher.c b/src/libstrongswan/plugins/gcrypt/gcrypt_hasher.c index 96c87614f..3155a4aa0 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_hasher.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_hasher.c @@ -43,13 +43,14 @@ METHOD(hasher_t, get_hash_size, size_t, return gcry_md_get_algo_dlen(gcry_md_get_algo(this->hd)); } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_gcrypt_hasher_t *this) { gcry_md_reset(this->hd); + return TRUE; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_gcrypt_hasher_t *this, chunk_t chunk, u_int8_t *hash) { gcry_md_write(this->hd, chunk.ptr, chunk.len); @@ -58,20 +59,18 @@ METHOD(hasher_t, get_hash, void, memcpy(hash, gcry_md_read(this->hd, 0), get_hash_size(this)); gcry_md_reset(this->hd); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_gcrypt_hasher_t *this, chunk_t chunk, chunk_t *hash) { if (hash) { *hash = chunk_alloc(get_hash_size(this)); - get_hash(this, chunk, hash->ptr); - } - else - { - get_hash(this, chunk, NULL); + return get_hash(this, chunk, hash->ptr); } + return get_hash(this, chunk, NULL); } METHOD(hasher_t, destroy, void, diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c index a48d4a133..5ebdcebce 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c @@ -132,9 +132,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(CRYPTER, ENCR_TWOFISH_CBC, 32), /* hashers */ PLUGIN_REGISTER(HASHER, gcrypt_hasher_create), + PLUGIN_PROVIDE(HASHER, HASH_SHA1), PLUGIN_PROVIDE(HASHER, HASH_MD4), PLUGIN_PROVIDE(HASHER, HASH_MD5), - PLUGIN_PROVIDE(HASHER, HASH_SHA1), PLUGIN_PROVIDE(HASHER, HASH_SHA224), PLUGIN_PROVIDE(HASHER, HASH_SHA256), PLUGIN_PROVIDE(HASHER, HASH_SHA384), diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rng.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rng.c index d29755de9..dc34a8d66 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rng.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rng.c @@ -35,7 +35,7 @@ struct private_gcrypt_rng_t { rng_quality_t quality; }; -METHOD(rng_t, get_bytes, void, +METHOD(rng_t, get_bytes, bool, private_gcrypt_rng_t *this, size_t bytes, u_int8_t *buffer) { switch (this->quality) @@ -50,13 +50,15 @@ METHOD(rng_t, get_bytes, void, gcry_randomize(buffer, bytes, GCRY_VERY_STRONG_RANDOM); break; } + return TRUE; } -METHOD(rng_t, allocate_bytes, void, +METHOD(rng_t, allocate_bytes, bool, private_gcrypt_rng_t *this, size_t bytes, chunk_t *chunk) { *chunk = chunk_alloc(bytes); get_bytes(this, chunk->len, chunk->ptr); + return TRUE; } METHOD(rng_t, destroy, void, diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c index eb38eea3b..9fdb2d45b 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c @@ -165,11 +165,11 @@ static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this, return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) { + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c index f8645da97..c54f2c0cf 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c @@ -121,11 +121,11 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this, gcry_sexp_t in, sig; hasher = lib->crypto->create_hasher(lib->crypto, algorithm); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) { + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", diff --git a/src/libstrongswan/plugins/gmp/Makefile.in b/src/libstrongswan/plugins/gmp/Makefile.in index 34a23312b..f1bb28c1f 100644 --- a/src/libstrongswan/plugins/gmp/Makefile.in +++ b/src/libstrongswan/plugins/gmp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_gmp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_gmp_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_gmp_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_gmp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c index e99502b27..7d232e4f1 100644 --- a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c @@ -230,8 +230,13 @@ static gmp_diffie_hellman_t *create_generic(diffie_hellman_group_t group, destroy(this); return NULL; } - - rng->allocate_bytes(rng, exp_len, &random); + if (!rng->allocate_bytes(rng, exp_len, &random)) + { + DBG1(DBG_LIB, "failed to allocate DH secret"); + rng->destroy(rng); + destroy(this); + return NULL; + } rng->destroy(rng); if (exp_len == this->p_len) diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index 1b6c20817..590ab6cb4 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -149,7 +149,12 @@ static status_t compute_prime(private_gmp_rsa_private_key_t *this, mpz_init(*prime); do { - rng->allocate_bytes(rng, prime_size, &random_bytes); + if (!rng->allocate_bytes(rng, prime_size, &random_bytes)) + { + DBG1(DBG_LIB, "failed to allocate random prime"); + rng->destroy(rng); + return FAILED; + } /* make sure the two most significant bits are set */ random_bytes.ptr[0] = random_bytes.ptr[0] | 0xC0; @@ -230,11 +235,11 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, } hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); - if (hasher == NULL) + if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) { + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); /* build DER-encoded digestInfo */ diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index 898892f5b..2d84f0025 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -252,7 +252,11 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, } /* build our own hash and compare */ - hasher->allocate_hash(hasher, data, &hash); + if (!hasher->allocate_hash(hasher, data, &hash)) + { + hasher->destroy(hasher); + goto end_parser; + } hasher->destroy(hasher); success = memeq(object.ptr, hash.ptr, hash.len); free(hash.ptr); @@ -314,7 +318,7 @@ METHOD(public_key_t, encrypt_, bool, { chunk_t em; u_char *pos; - int padding, i; + int padding; rng_t *rng; if (scheme != ENCRYPT_RSA_PKCS1) @@ -348,16 +352,12 @@ METHOD(public_key_t, encrypt_, bool, *pos++ = 0x02; /* fill with pseudo random octets */ - rng->get_bytes(rng, padding, pos); - - /* replace zero-valued random octets */ - for (i = 0; i < padding; i++) + if (!rng_get_bytes_not_zero(rng, padding, pos, TRUE)) { - while (*pos == 0) - { - rng->get_bytes(rng, 1, pos); - } - pos++; + DBG1(DBG_LIB, "failed to allocate padding"); + chunk_clear(&em); + rng->destroy(rng); + return FALSE; } rng->destroy(rng); diff --git a/src/libstrongswan/plugins/hmac/Makefile.am b/src/libstrongswan/plugins/hmac/Makefile.am index 77aa0ffd1..4faf321ef 100644 --- a/src/libstrongswan/plugins/hmac/Makefile.am +++ b/src/libstrongswan/plugins/hmac/Makefile.am @@ -10,7 +10,6 @@ plugin_LTLIBRARIES = libstrongswan-hmac.la endif libstrongswan_hmac_la_SOURCES = \ - hmac_plugin.h hmac_plugin.c hmac.h hmac.c \ - hmac_prf.h hmac_prf.c hmac_signer.h hmac_signer.c + hmac_plugin.h hmac_plugin.c hmac.h hmac.c libstrongswan_hmac_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/hmac/Makefile.in b/src/libstrongswan/plugins/hmac/Makefile.in index 5242764d4..aed35cf16 100644 --- a/src/libstrongswan/plugins/hmac/Makefile.in +++ b/src/libstrongswan/plugins/hmac/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -75,15 +76,14 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_hmac_la_LIBADD = -am_libstrongswan_hmac_la_OBJECTS = hmac_plugin.lo hmac.lo hmac_prf.lo \ - hmac_signer.lo +am_libstrongswan_hmac_la_OBJECTS = hmac_plugin.lo hmac.lo libstrongswan_hmac_la_OBJECTS = $(am_libstrongswan_hmac_la_OBJECTS) libstrongswan_hmac_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libstrongswan_hmac_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_hmac_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_hmac_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -286,8 +291,7 @@ AM_CFLAGS = -rdynamic @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-hmac.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-hmac.la libstrongswan_hmac_la_SOURCES = \ - hmac_plugin.h hmac_plugin.c hmac.h hmac.c \ - hmac_prf.h hmac_prf.c hmac_signer.h hmac_signer.c + hmac_plugin.h hmac_plugin.c hmac.h hmac.c libstrongswan_hmac_la_LDFLAGS = -module -avoid-version all: all-am @@ -375,8 +379,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_prf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hmac_signer.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/libstrongswan/plugins/hmac/hmac.c b/src/libstrongswan/plugins/hmac/hmac.c index 91294305e..44cb46b4d 100644 --- a/src/libstrongswan/plugins/hmac/hmac.c +++ b/src/libstrongswan/plugins/hmac/hmac.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -14,23 +15,25 @@ * for more details. */ -#include - #include "hmac.h" +#include +#include +#include -typedef struct private_hmac_t private_hmac_t; +typedef struct private_mac_t private_mac_t; /** - * Private data of a hmac_t object. + * Private data of a mac_t object. * * The variable names are the same as in the RFC. */ -struct private_hmac_t { +struct private_mac_t { + /** - * Public hmac_t interface. + * Implements mac_t interface */ - hmac_t public; + mac_t public; /** * Block size, as in RFC. @@ -53,8 +56,8 @@ struct private_hmac_t { chunk_t ipaded_key; }; -METHOD(hmac_t, get_mac, void, - private_hmac_t *this, chunk_t data, u_int8_t *out) +METHOD(mac_t, get_mac, bool, + private_mac_t *this, chunk_t data, u_int8_t *out) { /* H(K XOR opad, H(K XOR ipad, text)) * @@ -69,51 +72,28 @@ METHOD(hmac_t, get_mac, void, if (out == NULL) { /* append data to inner */ - this->h->get_hash(this->h, data, NULL); + return this->h->get_hash(this->h, data, NULL); } - else - { - /* append and do outer hash */ - inner.ptr = buffer; - inner.len = this->h->get_hash_size(this->h); - - /* complete inner */ - this->h->get_hash(this->h, data, buffer); - /* do outer */ - this->h->get_hash(this->h, this->opaded_key, NULL); - this->h->get_hash(this->h, inner, out); + /* append and do outer hash */ + inner.ptr = buffer; + inner.len = this->h->get_hash_size(this->h); - /* reinit for next call */ - this->h->get_hash(this->h, this->ipaded_key, NULL); - } + /* complete inner, do outer and reinit for next call */ + return this->h->get_hash(this->h, data, buffer) && + this->h->get_hash(this->h, this->opaded_key, NULL) && + this->h->get_hash(this->h, inner, out) && + this->h->get_hash(this->h, this->ipaded_key, NULL); } -METHOD(hmac_t, allocate_mac, void, - private_hmac_t *this, chunk_t data, chunk_t *out) -{ - /* allocate space and use get_mac */ - if (out == NULL) - { - /* append mode */ - get_mac(this, data, NULL); - } - else - { - out->len = this->h->get_hash_size(this->h); - out->ptr = malloc(out->len); - get_mac(this, data, out->ptr); - } -} - -METHOD(hmac_t, get_block_size, size_t, - private_hmac_t *this) +METHOD(mac_t, get_mac_size, size_t, + private_mac_t *this) { return this->h->get_hash_size(this->h); } -METHOD(hmac_t, set_key, void, - private_hmac_t *this, chunk_t key) +METHOD(mac_t, set_key, bool, + private_mac_t *this, chunk_t key) { int i; u_int8_t buffer[this->b]; @@ -123,7 +103,10 @@ METHOD(hmac_t, set_key, void, if (key.len > this->b) { /* if key is too long, it will be hashed */ - this->h->get_hash(this->h, key, buffer); + if (!this->h->get_hash(this->h, key, buffer)) + { + return FALSE; + } } else { @@ -139,12 +122,12 @@ METHOD(hmac_t, set_key, void, } /* begin hashing of inner pad */ - this->h->reset(this->h); - this->h->get_hash(this->h, this->ipaded_key, NULL); + return this->h->reset(this->h) && + this->h->get_hash(this->h, this->ipaded_key, NULL); } -METHOD(hmac_t, destroy, void, - private_hmac_t *this) +METHOD(mac_t, destroy, void, + private_mac_t *this) { this->h->destroy(this->h); chunk_clear(&this->opaded_key); @@ -153,17 +136,16 @@ METHOD(hmac_t, destroy, void, } /* - * Described in header + * Creates an mac_t object */ -hmac_t *hmac_create(hash_algorithm_t hash_algorithm) +static mac_t *hmac_create(hash_algorithm_t hash_algorithm) { - private_hmac_t *this; + private_mac_t *this; INIT(this, .public = { .get_mac = _get_mac, - .allocate_mac = _allocate_mac, - .get_block_size = _get_block_size, + .get_mac_size = _get_mac_size, .set_key = _set_key, .destroy = _destroy, }, @@ -202,3 +184,34 @@ hmac_t *hmac_create(hash_algorithm_t hash_algorithm) return &this->public; } + +/* + * Described in header + */ +prf_t *hmac_prf_create(pseudo_random_function_t algo) +{ + mac_t *hmac; + + hmac = hmac_create(hasher_algorithm_from_prf(algo)); + if (hmac) + { + return mac_prf_create(hmac); + } + return NULL; +} + +/* + * Described in header + */ +signer_t *hmac_signer_create(integrity_algorithm_t algo) +{ + mac_t *hmac; + size_t trunc; + + hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc)); + if (hmac) + { + return mac_signer_create(hmac, trunc); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/hmac/hmac.h b/src/libstrongswan/plugins/hmac/hmac.h index 1ed041596..bf66dd4aa 100644 --- a/src/libstrongswan/plugins/hmac/hmac.h +++ b/src/libstrongswan/plugins/hmac/hmac.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter + * Copyright (C) 2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -15,79 +14,34 @@ */ /** - * @defgroup hmac hmac + * Implements the message authentication algorithm described in RFC2104. + * + * It uses a hash function, which must be implemented as a hasher_t class. + * + * @defgroup hmac_mac mac * @{ @ingroup hmac_p */ #ifndef HMAC_H_ #define HMAC_H_ -typedef struct hmac_t hmac_t; - -#include +#include +#include /** - * Message authentication using hash functions. + * Creates a new prf_t object based on an HMAC. * - * This class implements the message authentication algorithm - * described in RFC2104. It uses a hash function, which must - * be implemented as a hasher_t class. + * @param algo algorithm to implement + * @return prf_t object, NULL if not supported */ -struct hmac_t { - /** - * Generate message authentication code. - * - * If buffer is NULL, no result is given back. A next call will - * append the data to already supplied data. If buffer is not NULL, - * the mac of all apended data is calculated, returned and the - * state of the hmac_t is reseted. - * - * @param data chunk of data to authenticate - * @param buffer pointer where the generated bytes will be written - */ - void (*get_mac) (hmac_t *this, chunk_t data, u_int8_t *buffer); - - /** - * Generates message authentication code and allocate space for them. - * - * If chunk is NULL, no result is given back. A next call will - * append the data to already supplied. If chunk is not NULL, - * the mac of all apended data is calculated, returned and the - * state of the hmac_t reset; - * - * @param data chunk of data to authenticate - * @param chunk chunk which will hold generated bytes - */ - void (*allocate_mac) (hmac_t *this, chunk_t data, chunk_t *chunk); - - /** - * Get the block size of this hmac_t object. - * - * @return block size in bytes - */ - size_t (*get_block_size) (hmac_t *this); - - /** - * Set the key for this hmac_t object. - * - * Any key length is accepted. - * - * @param key key to set - */ - void (*set_key) (hmac_t *this, chunk_t key); - - /** - * Destroys a hmac_t object. - */ - void (*destroy) (hmac_t *this); -}; +prf_t *hmac_prf_create(pseudo_random_function_t algo); /** - * Creates a new hmac_t object. + * Creates a new signer_t object based on an HMAC. * - * @param hash_algorithm hash algorithm to use - * @return hmac_t object, NULL if not supported + * @param algo algorithm to implement + * @return signer_t, NULL if not supported */ -hmac_t *hmac_create(hash_algorithm_t hash_algorithm); +signer_t *hmac_signer_create(integrity_algorithm_t algo); #endif /** HMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_plugin.c b/src/libstrongswan/plugins/hmac/hmac_plugin.c index 7d9ff3c67..f9c0c484b 100644 --- a/src/libstrongswan/plugins/hmac/hmac_plugin.c +++ b/src/libstrongswan/plugins/hmac/hmac_plugin.c @@ -16,8 +16,7 @@ #include "hmac_plugin.h" #include -#include "hmac_signer.h" -#include "hmac_prf.h" +#include "hmac.h" typedef struct private_hmac_plugin_t private_hmac_plugin_t; diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.c b/src/libstrongswan/plugins/hmac/hmac_prf.c deleted file mode 100644 index ca10612f9..000000000 --- a/src/libstrongswan/plugins/hmac/hmac_prf.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2005-2006 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "hmac_prf.h" - -#include "hmac.h" - - -typedef struct private_hmac_prf_t private_hmac_prf_t; - -/** - * Private data of a hma_prf_t object. - */ -struct private_hmac_prf_t { - /** - * Public hmac_prf_t interface. - */ - hmac_prf_t public; - - /** - * Hmac to use for generation. - */ - hmac_t *hmac; -}; - -METHOD(prf_t, get_bytes, void, - private_hmac_prf_t *this, chunk_t seed, u_int8_t *buffer) -{ - this->hmac->get_mac(this->hmac, seed, buffer); -} - -METHOD(prf_t, allocate_bytes, void, - private_hmac_prf_t *this, chunk_t seed, chunk_t *chunk) -{ - this->hmac->allocate_mac(this->hmac, seed, chunk); -} - -METHOD(prf_t, get_block_size, size_t, - private_hmac_prf_t *this) -{ - return this->hmac->get_block_size(this->hmac); -} - -METHOD(prf_t, get_key_size, size_t, - private_hmac_prf_t *this) -{ - /* for HMAC prfs, IKEv2 uses block size as key size */ - return this->hmac->get_block_size(this->hmac); -} - -METHOD(prf_t, set_key, void, - private_hmac_prf_t *this, chunk_t key) -{ - this->hmac->set_key(this->hmac, key); -} - -METHOD(prf_t, destroy, void, - private_hmac_prf_t *this) -{ - this->hmac->destroy(this->hmac); - free(this); -} - -/* - * Described in header. - */ -hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo) -{ - private_hmac_prf_t *this; - hmac_t *hmac; - - switch (algo) - { - case PRF_HMAC_SHA1: - hmac = hmac_create(HASH_SHA1); - break; - case PRF_HMAC_MD5: - hmac = hmac_create(HASH_MD5); - break; - case PRF_HMAC_SHA2_256: - hmac = hmac_create(HASH_SHA256); - break; - case PRF_HMAC_SHA2_384: - hmac = hmac_create(HASH_SHA384); - break; - case PRF_HMAC_SHA2_512: - hmac = hmac_create(HASH_SHA512); - break; - default: - return NULL; - } - if (hmac == NULL) - { - return NULL; - } - - INIT(this, - .public = { - .prf = { - .get_bytes = _get_bytes, - .allocate_bytes = _allocate_bytes, - .get_block_size = _get_block_size, - .get_key_size = _get_key_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .hmac = hmac, - ); - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/hmac/hmac_prf.h b/src/libstrongswan/plugins/hmac/hmac_prf.h deleted file mode 100644 index 29d7269ae..000000000 --- a/src/libstrongswan/plugins/hmac/hmac_prf.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup hmac_prf hmac_prf - * @{ @ingroup hmac_p - */ - -#ifndef PRF_HMAC_H_ -#define PRF_HMAC_H_ - -typedef struct hmac_prf_t hmac_prf_t; - -#include - -/** - * Implementation of prf_t interface using the HMAC algorithm. - * - * This simply wraps a hmac_t in a prf_t. More a question of - * interface matching. - */ -struct hmac_prf_t { - - /** - * Implements prf_t interface. - */ - prf_t prf; -}; - -/** - * Creates a new hmac_prf_t object. - * - * @param algo algorithm to implement - * @return hmac_prf_t object, NULL if hash not supported - */ -hmac_prf_t *hmac_prf_create(pseudo_random_function_t algo); - -#endif /** PRF_HMAC_SHA1_H_ @}*/ diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.c b/src/libstrongswan/plugins/hmac/hmac_signer.c deleted file mode 100644 index 511a3e3a5..000000000 --- a/src/libstrongswan/plugins/hmac/hmac_signer.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "hmac_signer.h" -#include "hmac.h" - -typedef struct private_hmac_signer_t private_hmac_signer_t; - -/** - * Private data structure with signing context. - */ -struct private_hmac_signer_t { - /** - * Public interface of hmac_signer_t. - */ - hmac_signer_t public; - - /** - * Assigned hmac function. - */ - hmac_t *hmac; - - /** - * Block size (truncation of HMAC Hash) - */ - size_t block_size; -}; - -METHOD(signer_t, get_signature, void, - private_hmac_signer_t *this, chunk_t data, u_int8_t *buffer) -{ - if (buffer == NULL) - { /* append mode */ - this->hmac->get_mac(this->hmac, data, NULL); - } - else - { - u_int8_t mac[this->hmac->get_block_size(this->hmac)]; - - this->hmac->get_mac(this->hmac, data, mac); - memcpy(buffer, mac, this->block_size); - } -} - -METHOD(signer_t, allocate_signature, void, - private_hmac_signer_t *this, chunk_t data, chunk_t *chunk) -{ - if (chunk == NULL) - { /* append mode */ - this->hmac->get_mac(this->hmac, data, NULL); - } - else - { - u_int8_t mac[this->hmac->get_block_size(this->hmac)]; - - this->hmac->get_mac(this->hmac, data, mac); - - chunk->ptr = malloc(this->block_size); - chunk->len = this->block_size; - - memcpy(chunk->ptr, mac, this->block_size); - } -} - -METHOD(signer_t, verify_signature, bool, - private_hmac_signer_t *this, chunk_t data, chunk_t signature) -{ - u_int8_t mac[this->hmac->get_block_size(this->hmac)]; - - this->hmac->get_mac(this->hmac, data, mac); - - if (signature.len != this->block_size) - { - return FALSE; - } - return memeq(signature.ptr, mac, this->block_size); -} - -METHOD(signer_t, get_key_size, size_t, - private_hmac_signer_t *this) -{ - return this->hmac->get_block_size(this->hmac); -} - -METHOD(signer_t, get_block_size, size_t, - private_hmac_signer_t *this) -{ - return this->block_size; -} - -METHOD(signer_t, set_key, void, - private_hmac_signer_t *this, chunk_t key) -{ - this->hmac->set_key(this->hmac, key); -} - -METHOD(signer_t, destroy, void, - private_hmac_signer_t *this) -{ - this->hmac->destroy(this->hmac); - free(this); -} - -/* - * Described in header - */ -hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo) -{ - private_hmac_signer_t *this; - hmac_t *hmac; - size_t trunc; - - switch (algo) - { - case AUTH_HMAC_SHA1_96: - hmac = hmac_create(HASH_SHA1); - trunc = 12; - break; - case AUTH_HMAC_SHA1_128: - hmac = hmac_create(HASH_SHA1); - trunc = 16; - break; - case AUTH_HMAC_SHA1_160: - hmac = hmac_create(HASH_SHA1); - trunc = 20; - break; - case AUTH_HMAC_MD5_96: - hmac = hmac_create(HASH_MD5); - trunc = 12; - break; - case AUTH_HMAC_MD5_128: - hmac = hmac_create(HASH_MD5); - trunc = 16; - break; - case AUTH_HMAC_SHA2_256_128: - hmac = hmac_create(HASH_SHA256); - trunc = 16; - break; - case AUTH_HMAC_SHA2_384_192: - hmac = hmac_create(HASH_SHA384); - trunc = 24; - break; - case AUTH_HMAC_SHA2_512_256: - hmac = hmac_create(HASH_SHA512); - trunc = 32; - break; - case AUTH_HMAC_SHA2_256_256: - hmac = hmac_create(HASH_SHA256); - trunc = 32; - break; - case AUTH_HMAC_SHA2_384_384: - hmac = hmac_create(HASH_SHA384); - trunc = 48; - break; - default: - return NULL; - } - - if (hmac == NULL) - { - return NULL; - } - - INIT(this, - .public = { - .signer = { - .get_signature = _get_signature, - .allocate_signature = _allocate_signature, - .verify_signature = _verify_signature, - .get_key_size = _get_key_size, - .get_block_size = _get_block_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .block_size = min(trunc, hmac->get_block_size(hmac)), - .hmac = hmac, - ); - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/hmac/hmac_signer.h b/src/libstrongswan/plugins/hmac/hmac_signer.h deleted file mode 100644 index 5e798683b..000000000 --- a/src/libstrongswan/plugins/hmac/hmac_signer.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2005-2008 Martin Willi - * Copyright (C) 2005 Jan Hutter - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup hmac_signer hmac_signer - * @{ @ingroup hmac_p - */ - -#ifndef HMAC_SIGNER_H_ -#define HMAC_SIGNER_H_ - -typedef struct hmac_signer_t hmac_signer_t; - -#include - -/** - * Implementation of signer_t interface using HMAC. - * - * HMAC uses a standard hash function implemented in a hasher_t to build a MAC. - */ -struct hmac_signer_t { - - /** - * Implements signer_t interface. - */ - signer_t signer; -}; - -/** - * Creates a new hmac_signer_t. - * - * HMAC signatures are often truncated to shorten them to a more usable, but - * still secure enough length. - * Block size must be equal or smaller then the hash algorithms hash. - * - * @param algo algorithm to implement - * @return hmac_signer_t, NULL if not supported - */ -hmac_signer_t *hmac_signer_create(integrity_algorithm_t algo); - -#endif /** HMAC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/plugins/ldap/Makefile.in b/src/libstrongswan/plugins/ldap/Makefile.in index 851df5667..d11feddb1 100644 --- a/src/libstrongswan/plugins/ldap/Makefile.in +++ b/src/libstrongswan/plugins/ldap/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_ldap_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_ldap_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_ldap_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_ldap_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/ldap/ldap_fetcher.c b/src/libstrongswan/plugins/ldap/ldap_fetcher.c index fc6114b0a..75f964853 100644 --- a/src/libstrongswan/plugins/ldap/ldap_fetcher.c +++ b/src/libstrongswan/plugins/ldap/ldap_fetcher.c @@ -176,13 +176,14 @@ METHOD(fetcher_t, set_option, bool, switch (option) { case FETCH_TIMEOUT: - { this->timeout = va_arg(args, u_int); - return TRUE; - } + break; default: + va_end(args); return FALSE; } + va_end(args); + return TRUE; } METHOD(fetcher_t, destroy, void, diff --git a/src/libstrongswan/plugins/md4/Makefile.in b/src/libstrongswan/plugins/md4/Makefile.in index f5b06a0df..14b6370f4 100644 --- a/src/libstrongswan/plugins/md4/Makefile.in +++ b/src/libstrongswan/plugins/md4/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_md4_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_md4_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_md4_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_md4_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/md4/md4_hasher.c b/src/libstrongswan/plugins/md4/md4_hasher.c index 6a31017c2..06c9ec2f8 100644 --- a/src/libstrongswan/plugins/md4/md4_hasher.c +++ b/src/libstrongswan/plugins/md4/md4_hasher.c @@ -266,20 +266,32 @@ static void MD4Final (private_md4_hasher_t *this, u_int8_t digest[16]) } } +METHOD(hasher_t, reset, bool, + private_md4_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xefcdab89; + this->state[2] = 0x98badcfe; + this->state[3] = 0x10325476; + this->count[0] = 0; + this->count[1] = 0; + return TRUE; +} -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_md4_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { MD4Update(this, chunk.ptr, chunk.len); if (buffer != NULL) { MD4Final(this, buffer); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); + reset(this); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_md4_hasher_t *this, chunk_t chunk, chunk_t *hash) { chunk_t allocated_hash; @@ -291,10 +303,11 @@ METHOD(hasher_t, allocate_hash, void, allocated_hash.len = HASH_SIZE_MD4; MD4Final(this, allocated_hash.ptr); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); + reset(this); *hash = allocated_hash; } + return TRUE; } METHOD(hasher_t, get_hash_size, size_t, @@ -303,17 +316,6 @@ METHOD(hasher_t, get_hash_size, size_t, return HASH_SIZE_MD4; } -METHOD(hasher_t, reset, void, - private_md4_hasher_t *this) -{ - this->state[0] = 0x67452301; - this->state[1] = 0xefcdab89; - this->state[2] = 0x98badcfe; - this->state[3] = 0x10325476; - this->count[0] = 0; - this->count[1] = 0; -} - METHOD(hasher_t, destroy, void, private_md4_hasher_t *this) { diff --git a/src/libstrongswan/plugins/md5/Makefile.in b/src/libstrongswan/plugins/md5/Makefile.in index f7762c37e..ba228f8ea 100644 --- a/src/libstrongswan/plugins/md5/Makefile.in +++ b/src/libstrongswan/plugins/md5/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_md5_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_md5_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_md5_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_md5_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/md5/md5_hasher.c b/src/libstrongswan/plugins/md5/md5_hasher.c index 45c2391ef..99b505e58 100644 --- a/src/libstrongswan/plugins/md5/md5_hasher.c +++ b/src/libstrongswan/plugins/md5/md5_hasher.c @@ -299,33 +299,42 @@ static void MD5Final (private_md5_hasher_t *this, u_int8_t digest[16]) } } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, reset, bool, + private_md5_hasher_t *this) +{ + this->state[0] = 0x67452301; + this->state[1] = 0xefcdab89; + this->state[2] = 0x98badcfe; + this->state[3] = 0x10325476; + this->count[0] = 0; + this->count[1] = 0; + + return TRUE; +} + +METHOD(hasher_t, get_hash, bool, private_md5_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { MD5Update(this, chunk.ptr, chunk.len); if (buffer != NULL) { MD5Final(this, buffer); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); + reset(this); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_md5_hasher_t *this, chunk_t chunk, chunk_t *hash) { - chunk_t allocated_hash; - MD5Update(this, chunk.ptr, chunk.len); if (hash != NULL) { - allocated_hash.ptr = malloc(HASH_SIZE_MD5); - allocated_hash.len = HASH_SIZE_MD5; - - MD5Final(this, allocated_hash.ptr); - this->public.hasher_interface.reset(&(this->public.hasher_interface)); - - *hash = allocated_hash; + *hash = chunk_alloc(HASH_SIZE_MD5); + MD5Final(this, hash->ptr); + reset(this); } + return TRUE; } METHOD(hasher_t, get_hash_size, size_t, @@ -334,17 +343,6 @@ METHOD(hasher_t, get_hash_size, size_t, return HASH_SIZE_MD5; } -METHOD(hasher_t, reset, void, - private_md5_hasher_t *this) -{ - this->state[0] = 0x67452301; - this->state[1] = 0xefcdab89; - this->state[2] = 0x98badcfe; - this->state[3] = 0x10325476; - this->count[0] = 0; - this->count[1] = 0; -} - METHOD(hasher_t, destroy, void, private_md5_hasher_t *this) { diff --git a/src/libstrongswan/plugins/md5/md5_plugin.c b/src/libstrongswan/plugins/md5/md5_plugin.c index a3ad7b305..4a61af618 100644 --- a/src/libstrongswan/plugins/md5/md5_plugin.c +++ b/src/libstrongswan/plugins/md5/md5_plugin.c @@ -51,8 +51,6 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_md5_plugin_t *this) { - lib->crypto->remove_hasher(lib->crypto, - (hasher_constructor_t)md5_hasher_create); free(this); } diff --git a/src/libstrongswan/plugins/mysql/Makefile.in b/src/libstrongswan/plugins/mysql/Makefile.in index 5025a0eb8..88dba0967 100644 --- a/src/libstrongswan/plugins/mysql/Makefile.in +++ b/src/libstrongswan/plugins/mysql/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_mysql_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_mysql_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_mysql_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/mysql/mysql_database.c b/src/libstrongswan/plugins/mysql/mysql_database.c index 25ea42a4f..1a20a804a 100644 --- a/src/libstrongswan/plugins/mysql/mysql_database.c +++ b/src/libstrongswan/plugins/mysql/mysql_database.c @@ -472,6 +472,7 @@ static bool mysql_enumerator_enumerate(mysql_enumerator_t *this, ...) break; } } + va_end(args); return TRUE; } diff --git a/src/libstrongswan/plugins/nonce/Makefile.am b/src/libstrongswan/plugins/nonce/Makefile.am new file mode 100644 index 000000000..0a2ccfc08 --- /dev/null +++ b/src/libstrongswan/plugins/nonce/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-nonce.la +else +plugin_LTLIBRARIES = libstrongswan-nonce.la +endif + +libstrongswan_nonce_la_SOURCES = \ + nonce_plugin.h nonce_plugin.c \ + nonce_nonceg.c nonce_nonceg.h + +libstrongswan_nonce_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/nonce/Makefile.in b/src/libstrongswan/plugins/nonce/Makefile.in new file mode 100644 index 000000000..7ce23b4d9 --- /dev/null +++ b/src/libstrongswan/plugins/nonce/Makefile.in @@ -0,0 +1,617 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/libstrongswan/plugins/nonce +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ + $(top_srcdir)/m4/config/ltoptions.m4 \ + $(top_srcdir)/m4/config/ltsugar.m4 \ + $(top_srcdir)/m4/config/ltversion.m4 \ + $(top_srcdir)/m4/config/lt~obsolete.m4 \ + $(top_srcdir)/m4/macros/with.m4 \ + $(top_srcdir)/m4/macros/enable-disable.m4 \ + $(top_srcdir)/m4/macros/add-plugin.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) +libstrongswan_nonce_la_LIBADD = +am_libstrongswan_nonce_la_OBJECTS = nonce_plugin.lo nonce_nonceg.lo +libstrongswan_nonce_la_OBJECTS = $(am_libstrongswan_nonce_la_OBJECTS) +libstrongswan_nonce_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libstrongswan_nonce_la_LDFLAGS) $(LDFLAGS) -o $@ +@MONOLITHIC_FALSE@am_libstrongswan_nonce_la_rpath = -rpath \ +@MONOLITHIC_FALSE@ $(plugindir) +@MONOLITHIC_TRUE@am_libstrongswan_nonce_la_rpath = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libstrongswan_nonce_la_SOURCES) +DIST_SOURCES = $(libstrongswan_nonce_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BFDLIB = @BFDLIB@ +BTLIB = @BTLIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GPERF = @GPERF@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MYSQLCFLAG = @MYSQLCFLAG@ +MYSQLCONFIG = @MYSQLCONFIG@ +MYSQLLIB = @MYSQLLIB@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PTHREADLIB = @PTHREADLIB@ +RANLIB = @RANLIB@ +RTLIB = @RTLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SOCKLIB = @SOCKLIB@ +STRIP = @STRIP@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +attest_plugins = @attest_plugins@ +axis2c_CFLAGS = @axis2c_CFLAGS@ +axis2c_LIBS = @axis2c_LIBS@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ +clearsilver_LIBS = @clearsilver_LIBS@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusservicedir = @dbusservicedir@ +dev_headers = @dev_headers@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ +h_plugins = @h_plugins@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +imcvdir = @imcvdir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ +ipsecdir = @ipsecdir@ +ipsecgroup = @ipsecgroup@ +ipseclibdir = @ipseclibdir@ +ipsecuser = @ipsecuser@ +libdir = @libdir@ +libexecdir = @libexecdir@ +linux_headers = @linux_headers@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +maemo_CFLAGS = @maemo_CFLAGS@ +maemo_LIBS = @maemo_LIBS@ +manager_plugins = @manager_plugins@ +mandir = @mandir@ +medsrv_plugins = @medsrv_plugins@ +mkdir_p = @mkdir_p@ +nm_CFLAGS = @nm_CFLAGS@ +nm_LIBS = @nm_LIBS@ +nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ +oldincludedir = @oldincludedir@ +openac_plugins = @openac_plugins@ +p_plugins = @p_plugins@ +pcsclite_CFLAGS = @pcsclite_CFLAGS@ +pcsclite_LIBS = @pcsclite_LIBS@ +pdfdir = @pdfdir@ +piddir = @piddir@ +pki_plugins = @pki_plugins@ +plugindir = @plugindir@ +pool_plugins = @pool_plugins@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +random_device = @random_device@ +resolv_conf = @resolv_conf@ +routing_table = @routing_table@ +routing_table_prio = @routing_table_prio@ +s_plugins = @s_plugins@ +sbindir = @sbindir@ +scepclient_plugins = @scepclient_plugins@ +scripts_plugins = @scripts_plugins@ +sharedstatedir = @sharedstatedir@ +soup_CFLAGS = @soup_CFLAGS@ +soup_LIBS = @soup_LIBS@ +srcdir = @srcdir@ +starter_plugins = @starter_plugins@ +strongswan_conf = @strongswan_conf@ +sysconfdir = @sysconfdir@ +systemdsystemunitdir = @systemdsystemunitdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +urandom_device = @urandom_device@ +xml_CFLAGS = @xml_CFLAGS@ +xml_LIBS = @xml_LIBS@ +INCLUDES = -I$(top_srcdir)/src/libstrongswan +AM_CFLAGS = -rdynamic +@MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-nonce.la +@MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-nonce.la +libstrongswan_nonce_la_SOURCES = \ + nonce_plugin.h nonce_plugin.c \ + nonce_nonceg.c nonce_nonceg.h + +libstrongswan_nonce_la_LDFLAGS = -module -avoid-version +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/libstrongswan/plugins/nonce/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/libstrongswan/plugins/nonce/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libstrongswan-nonce.la: $(libstrongswan_nonce_la_OBJECTS) $(libstrongswan_nonce_la_DEPENDENCIES) + $(libstrongswan_nonce_la_LINK) $(am_libstrongswan_nonce_la_rpath) $(libstrongswan_nonce_la_OBJECTS) $(libstrongswan_nonce_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonce_nonceg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonce_plugin.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES clean-pluginLTLIBRARIES \ + ctags distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libstrongswan/plugins/nonce/nonce_nonceg.c b/src/libstrongswan/plugins/nonce/nonce_nonceg.c new file mode 100644 index 000000000..0402e3574 --- /dev/null +++ b/src/libstrongswan/plugins/nonce/nonce_nonceg.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "nonce_nonceg.h" + +#include + +typedef struct private_nonce_nonceg_t private_nonce_nonceg_t; + +/** + * Private data of a nonce_nonceg_t object. + */ +struct private_nonce_nonceg_t { + + /** + * Public nonce_nonceg_t interface. + */ + nonce_nonceg_t public; + + /** + * Random number generator + */ + rng_t* rng; +}; + +METHOD(nonce_gen_t, get_nonce, bool, + private_nonce_nonceg_t *this, size_t size, u_int8_t *buffer) +{ + return this->rng->get_bytes(this->rng, size, buffer); +} + +METHOD(nonce_gen_t, allocate_nonce, bool, + private_nonce_nonceg_t *this, size_t size, chunk_t *chunk) +{ + return this->rng->allocate_bytes(this->rng, size, chunk); +} + +METHOD(nonce_gen_t, destroy, void, + private_nonce_nonceg_t *this) +{ + DESTROY_IF(this->rng); + free(this); +} + +/* + * Described in header. + */ +nonce_nonceg_t *nonce_nonceg_create() +{ + private_nonce_nonceg_t *this; + + INIT(this, + .public = { + .nonce_gen = { + .get_nonce = _get_nonce, + .allocate_nonce = _allocate_nonce, + .destroy = _destroy, + }, + }, + ); + + this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!this->rng) + { + DBG1(DBG_LIB, "no RNG found for quality %N", rng_quality_names, + RNG_WEAK); + destroy(this); + return NULL; + } + + return &this->public; +} diff --git a/src/libstrongswan/plugins/nonce/nonce_nonceg.h b/src/libstrongswan/plugins/nonce/nonce_nonceg.h new file mode 100644 index 000000000..2ae0c97de --- /dev/null +++ b/src/libstrongswan/plugins/nonce/nonce_nonceg.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nonce_nonceg nonce_nonceg + * @{ @ingroup nonce_p + */ + +#ifndef NONCE_NONCEG_H_ +#define NONCE_NONCEG_H_ + +typedef struct nonce_nonceg_t nonce_nonceg_t; + +#include + +/** + * nonce_gen_t implementation using an rng plugin + */ +struct nonce_nonceg_t { + + /** + * Implements nonce_gen_t. + */ + nonce_gen_t nonce_gen; +}; + +/** + * Creates an nonce_nonceg_t instance. + * + * @return created nonce_nonceg_t + */ +nonce_nonceg_t *nonce_nonceg_create(); + +#endif /** NONCE_NONCEG_H_ @} */ diff --git a/src/libstrongswan/plugins/nonce/nonce_plugin.c b/src/libstrongswan/plugins/nonce/nonce_plugin.c new file mode 100644 index 000000000..90f2e8fac --- /dev/null +++ b/src/libstrongswan/plugins/nonce/nonce_plugin.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "nonce_plugin.h" + +#include +#include "nonce_nonceg.h" + +typedef struct private_nonce_plugin_t private_nonce_plugin_t; + +/** + * private data of nonce_plugin + */ +struct private_nonce_plugin_t { + + /** + * public functions + */ + nonce_plugin_t public; +}; + +METHOD(plugin_t, get_name, char*, + private_nonce_plugin_t *this) +{ + return "nonce"; +} + +METHOD(plugin_t, get_features, int, + private_nonce_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_REGISTER(NONCE_GEN, nonce_nonceg_create), + PLUGIN_PROVIDE(NONCE_GEN), + PLUGIN_DEPENDS(RNG, RNG_WEAK), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + private_nonce_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *nonce_plugin_create() +{ + private_nonce_plugin_t *this; + + INIT(this, + .public = { + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + }, + ); + + return &this->public.plugin; +} diff --git a/src/libstrongswan/plugins/nonce/nonce_plugin.h b/src/libstrongswan/plugins/nonce/nonce_plugin.h new file mode 100644 index 000000000..f4be1c3a8 --- /dev/null +++ b/src/libstrongswan/plugins/nonce/nonce_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Adrian-Ken Rueegsegger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup nonce_p nonce + * @ingroup plugins + * + * @defgroup nonce_plugin nonce_plugin + * @{ @ingroup nonce_p + */ + +#ifndef NONCE_PLUGIN_H_ +#define NONCE_PLUGIN_H_ + +#include + +typedef struct nonce_plugin_t nonce_plugin_t; + +/** + * Plugin implementing a nonce generator using an RNG. + */ +struct nonce_plugin_t { + + /** + * Implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** NONCE_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/Makefile.am b/src/libstrongswan/plugins/openssl/Makefile.am index 5c845a19c..c59888663 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.am +++ b/src/libstrongswan/plugins/openssl/Makefile.am @@ -22,7 +22,9 @@ libstrongswan_openssl_la_SOURCES = \ openssl_ec_private_key.c openssl_ec_private_key.h \ openssl_ec_public_key.c openssl_ec_public_key.h \ openssl_x509.c openssl_x509.h \ - openssl_crl.c openssl_crl.h + openssl_crl.c openssl_crl.h \ + openssl_rng.c openssl_rng.h \ + openssl_hmac.c openssl_hmac.h libstrongswan_openssl_la_LDFLAGS = -module -avoid-version libstrongswan_openssl_la_LIBADD = -lcrypto diff --git a/src/libstrongswan/plugins/openssl/Makefile.in b/src/libstrongswan/plugins/openssl/Makefile.in index 8994ff1b4..ada44ead3 100644 --- a/src/libstrongswan/plugins/openssl/Makefile.in +++ b/src/libstrongswan/plugins/openssl/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -80,7 +81,8 @@ am_libstrongswan_openssl_la_OBJECTS = openssl_plugin.lo \ openssl_sha1_prf.lo openssl_diffie_hellman.lo \ openssl_rsa_private_key.lo openssl_rsa_public_key.lo \ openssl_ec_diffie_hellman.lo openssl_ec_private_key.lo \ - openssl_ec_public_key.lo openssl_x509.lo openssl_crl.lo + openssl_ec_public_key.lo openssl_x509.lo openssl_crl.lo \ + openssl_rng.lo openssl_hmac.lo libstrongswan_openssl_la_OBJECTS = \ $(am_libstrongswan_openssl_la_OBJECTS) libstrongswan_openssl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @@ -89,7 +91,7 @@ libstrongswan_openssl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_openssl_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_openssl_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -115,6 +117,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -209,11 +212,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -230,11 +236,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -250,6 +257,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -259,7 +267,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -304,7 +311,9 @@ libstrongswan_openssl_la_SOURCES = \ openssl_ec_private_key.c openssl_ec_private_key.h \ openssl_ec_public_key.c openssl_ec_public_key.h \ openssl_x509.c openssl_x509.h \ - openssl_crl.c openssl_crl.h + openssl_crl.c openssl_crl.h \ + openssl_rng.c openssl_rng.h \ + openssl_hmac.c openssl_hmac.h libstrongswan_openssl_la_LDFLAGS = -module -avoid-version libstrongswan_openssl_la_LIBADD = -lcrypto @@ -398,7 +407,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_private_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_ec_public_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hasher.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_hmac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_plugin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rng.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rsa_private_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_rsa_public_key.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/openssl_sha1_prf.Plo@am__quote@ diff --git a/src/libstrongswan/plugins/openssl/openssl_crl.c b/src/libstrongswan/plugins/openssl/openssl_crl.c index 9a9efb2b6..e529ff8a5 100644 --- a/src/libstrongswan/plugins/openssl/openssl_crl.c +++ b/src/libstrongswan/plugins/openssl/openssl_crl.c @@ -225,7 +225,8 @@ METHOD(certificate_t, has_subject_or_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_openssl_crl_t *this, certificate_t *issuer) + private_openssl_crl_t *this, certificate_t *issuer, + signature_scheme_t *scheme) { chunk_t fingerprint, tbs; public_key_t *key; @@ -270,6 +271,10 @@ METHOD(certificate_t, issued_by, bool, openssl_asn1_str2chunk(this->crl->signature)); free(tbs.ptr); key->destroy(key); + if (valid && scheme) + { + *scheme = this->scheme; + } return valid; } diff --git a/src/libstrongswan/plugins/openssl/openssl_crypter.c b/src/libstrongswan/plugins/openssl/openssl_crypter.c index cd9a3bd4a..07b96b320 100644 --- a/src/libstrongswan/plugins/openssl/openssl_crypter.c +++ b/src/libstrongswan/plugins/openssl/openssl_crypter.c @@ -90,7 +90,7 @@ static char* lookup_algorithm(u_int16_t ikev2_algo, size_t *key_size) /** * Do the actual en/decryption in an EVP context */ -static void crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv, +static bool crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst, int enc) { int len; @@ -104,25 +104,26 @@ static void crypt(private_openssl_crypter_t *this, chunk_t data, chunk_t iv, } EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); - EVP_CipherInit_ex(&ctx, this->cipher, NULL, NULL, NULL, enc); - EVP_CIPHER_CTX_set_padding(&ctx, 0); /* disable padding */ - EVP_CIPHER_CTX_set_key_length(&ctx, this->key.len); - EVP_CipherInit_ex(&ctx, NULL, NULL, this->key.ptr, iv.ptr, enc); - EVP_CipherUpdate(&ctx, out, &len, data.ptr, data.len); - EVP_CipherFinal_ex(&ctx, out + len, &len); /* since padding is disabled this does nothing */ - EVP_CIPHER_CTX_cleanup(&ctx); + return EVP_CipherInit_ex(&ctx, this->cipher, NULL, NULL, NULL, enc) && + EVP_CIPHER_CTX_set_padding(&ctx, 0) /* disable padding */ && + EVP_CIPHER_CTX_set_key_length(&ctx, this->key.len) && + EVP_CipherInit_ex(&ctx, NULL, NULL, this->key.ptr, iv.ptr, enc) && + EVP_CipherUpdate(&ctx, out, &len, data.ptr, data.len) && + /* since padding is disabled this does nothing */ + EVP_CipherFinal_ex(&ctx, out + len, &len) && + EVP_CIPHER_CTX_cleanup(&ctx); } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_openssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { - crypt(this, data, iv, dst, 0); + return crypt(this, data, iv, dst, 0); } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_openssl_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { - crypt(this, data, iv, dst, 1); + return crypt(this, data, iv, dst, 1); } METHOD(crypter_t, get_block_size, size_t, @@ -143,10 +144,11 @@ METHOD(crypter_t, get_key_size, size_t, return this->key.len; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_openssl_crypter_t *this, chunk_t key) { memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len)); + return TRUE; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c index 7461695ad..9cb68a3ab 100644 --- a/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_ec_public_key.c @@ -221,13 +221,13 @@ bool openssl_ec_fingerprint(EC_KEY *ec, cred_encoding_type_t type, chunk_t *fp) return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, key, fp)) { DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); + DESTROY_IF(hasher); free(key.ptr); return FALSE; } - hasher->allocate_hash(hasher, key, fp); hasher->destroy(hasher); free(key.ptr); lib->encoding->cache(lib->encoding, type, ec, *fp); diff --git a/src/libstrongswan/plugins/openssl/openssl_hasher.c b/src/libstrongswan/plugins/openssl/openssl_hasher.c index d81f4b21e..50b14698b 100644 --- a/src/libstrongswan/plugins/openssl/openssl_hasher.c +++ b/src/libstrongswan/plugins/openssl/openssl_hasher.c @@ -40,91 +40,45 @@ struct private_openssl_hasher_t { EVP_MD_CTX *ctx; }; -/** - * Mapping from the algorithms defined in IKEv2 to - * OpenSSL algorithm names - */ -typedef struct { - /** - * Identifier specified in IKEv2 - */ - int ikev2_id; - - /** - * Name of the algorithm, as used in OpenSSL - */ - char *name; -} openssl_algorithm_t; - -#define END_OF_LIST -1 - -/** - * Algorithms for integrity - */ -static openssl_algorithm_t integrity_algs[] = { - {HASH_MD2, "md2"}, - {HASH_MD5, "md5"}, - {HASH_SHA1, "sha1"}, - {HASH_SHA224, "sha224"}, - {HASH_SHA256, "sha256"}, - {HASH_SHA384, "sha384"}, - {HASH_SHA512, "sha512"}, - {HASH_MD4, "md4"}, - {END_OF_LIST, NULL}, -}; - -/** - * Look up an OpenSSL algorithm name - */ -static char* lookup_algorithm(openssl_algorithm_t *openssl_algo, - u_int16_t ikev2_algo) -{ - while (openssl_algo->ikev2_id != END_OF_LIST) - { - if (ikev2_algo == openssl_algo->ikev2_id) - { - return openssl_algo->name; - } - openssl_algo++; - } - return NULL; -} - METHOD(hasher_t, get_hash_size, size_t, private_openssl_hasher_t *this) { return this->hasher->md_size; } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_openssl_hasher_t *this) { - EVP_DigestInit_ex(this->ctx, this->hasher, NULL); + return EVP_DigestInit_ex(this->ctx, this->hasher, NULL) == 1; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_openssl_hasher_t *this, chunk_t chunk, u_int8_t *hash) { - EVP_DigestUpdate(this->ctx, chunk.ptr, chunk.len); + if (EVP_DigestUpdate(this->ctx, chunk.ptr, chunk.len) != 1) + { + return FALSE; + } if (hash) { - EVP_DigestFinal_ex(this->ctx, hash, NULL); - reset(this); + if (EVP_DigestFinal_ex(this->ctx, hash, NULL) != 1) + { + return FALSE; + } + return reset(this); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_openssl_hasher_t *this, chunk_t chunk, chunk_t *hash) { if (hash) { *hash = chunk_alloc(get_hash_size(this)); - get_hash(this, chunk, hash->ptr); - } - else - { - get_hash(this, chunk, NULL); + return get_hash(this, chunk, hash->ptr); } + return get_hash(this, chunk, NULL); } METHOD(hasher_t, destroy, void, @@ -140,11 +94,11 @@ METHOD(hasher_t, destroy, void, openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo) { private_openssl_hasher_t *this; + char* name; - char* name = lookup_algorithm(integrity_algs, algo); + name = enum_to_name(hash_algorithm_short_names, algo); if (!name) { - /* algo unavailable */ return NULL; } @@ -171,7 +125,11 @@ openssl_hasher_t *openssl_hasher_create(hash_algorithm_t algo) this->ctx = EVP_MD_CTX_create(); /* initialization */ - reset(this); + if (!reset(this)) + { + destroy(this); + return NULL; + } return &this->public; } diff --git a/src/libstrongswan/plugins/openssl/openssl_hmac.c b/src/libstrongswan/plugins/openssl/openssl_hmac.c new file mode 100644 index 000000000..5d05425d3 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_hmac.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* + * Copyright (C) 2012 Aleksandr Grinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include + +#include "openssl_hmac.h" + +#include +#include +#include + +typedef struct private_mac_t private_mac_t; + +/** + * Private data of a mac_t object. + */ +struct private_mac_t { + + /** + * Public interface + */ + mac_t public; + + /** + * Hasher to use + */ + const EVP_MD *hasher; + + /** + * Current HMAC context + */ + HMAC_CTX hmac; +}; + +METHOD(mac_t, set_key, bool, + private_mac_t *this, chunk_t key) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + return HMAC_Init_ex(&this->hmac, key.ptr, key.len, this->hasher, NULL); +#else /* OPENSSL_VERSION_NUMBER < 1.0 */ + HMAC_Init_ex(&this->hmac, key.ptr, key.len, this->hasher, NULL); + return TRUE; +#endif +} + +METHOD(mac_t, get_mac, bool, + private_mac_t *this, chunk_t data, u_int8_t *out) +{ +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + if (!HMAC_Update(&this->hmac, data.ptr, data.len)) + { + return FALSE; + } + if (out == NULL) + { + return TRUE; + } + if (!HMAC_Final(&this->hmac, out, NULL)) + { + return FALSE; + } +#else /* OPENSSL_VERSION_NUMBER < 1.0 */ + HMAC_Update(&this->hmac, data.ptr, data.len); + if (out == NULL) + { + return TRUE; + } + HMAC_Final(&this->hmac, out, NULL); +#endif + return set_key(this, chunk_empty); +} + +METHOD(mac_t, get_mac_size, size_t, + private_mac_t *this) +{ + return EVP_MD_size(this->hasher); +} + +METHOD(mac_t, destroy, void, + private_mac_t *this) +{ + HMAC_CTX_cleanup(&this->hmac); + free(this); +} + +/* + * Create an OpenSSL-backed implementation of the mac_t interface + */ +static mac_t *hmac_create(hash_algorithm_t algo) +{ + private_mac_t *this; + char *name; + + name = enum_to_name(hash_algorithm_short_names, algo); + if (!name) + { + return NULL; + } + + INIT(this, + .public = { + .get_mac = _get_mac, + .get_mac_size = _get_mac_size, + .set_key = _set_key, + .destroy = _destroy, + }, + .hasher = EVP_get_digestbyname(name), + ); + + if (!this->hasher) + { + free(this); + return NULL; + } + + HMAC_CTX_init(&this->hmac); + if (!set_key(this, chunk_empty)) + { + destroy(this); + return NULL; + } + + return &this->public; +} + +/* + * Described in header + */ +prf_t *openssl_hmac_prf_create(pseudo_random_function_t algo) +{ + mac_t *hmac; + + hmac = hmac_create(hasher_algorithm_from_prf(algo)); + if (hmac) + { + return mac_prf_create(hmac); + } + return NULL; +} + +/* + * Described in header + */ +signer_t *openssl_hmac_signer_create(integrity_algorithm_t algo) +{ + mac_t *hmac; + size_t trunc; + + hmac = hmac_create(hasher_algorithm_from_integrity(algo, &trunc)); + if (hmac) + { + return mac_signer_create(hmac, trunc); + } + return NULL; +} + diff --git a/src/libstrongswan/plugins/openssl/openssl_hmac.h b/src/libstrongswan/plugins/openssl/openssl_hmac.h new file mode 100644 index 000000000..95ab6bfc3 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_hmac.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * Implements HMAC based PRF and signer using OpenSSL's HMAC functions. + * + * @defgroup openssl_hmac openssl_hmac + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_HMAC_H_ +#define OPENSSL_HMAC_H_ + +#include +#include + +/** + * Creates a new prf_t object based on an HMAC. + * + * @param algo algorithm to implement + * @return prf_t object, NULL if not supported + */ +prf_t *openssl_hmac_prf_create(pseudo_random_function_t algo); + +/** + * Creates a new signer_t object based on an HMAC. + * + * @param algo algorithm to implement + * @return signer_t, NULL if not supported + */ +signer_t *openssl_hmac_signer_create(integrity_algorithm_t algo); + +#endif /** OPENSSL_HMAC_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index c93ceacc9..b69de981e 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -40,6 +40,8 @@ #include "openssl_ec_public_key.h" #include "openssl_x509.h" #include "openssl_crl.h" +#include "openssl_rng.h" +#include "openssl_hmac.h" typedef struct private_openssl_plugin_t private_openssl_plugin_t; @@ -127,7 +129,9 @@ static void destroy_function(struct CRYPTO_dynlock_value *lock, */ static unsigned long id_function(void) { - return (unsigned long)thread_current_id(); + /* ensure the thread ID is never zero, otherwise OpenSSL might try to + * acquire locks recursively */ + return 1 + (unsigned long)thread_current_id(); } /** @@ -170,7 +174,11 @@ static bool seed_rng() return FALSE; } } - rng->get_bytes(rng, sizeof(buf), buf); + if (!rng->get_bytes(rng, sizeof(buf), buf)) + { + rng->destroy(rng); + return FALSE; + } RAND_seed(buf, sizeof(buf)); } DESTROY_IF(rng); @@ -260,6 +268,41 @@ METHOD(plugin_t, get_features, int, PLUGIN_REGISTER(PRF, openssl_sha1_prf_create), PLUGIN_PROVIDE(PRF, PRF_KEYED_SHA1), #endif +#ifndef OPENSSL_NO_HMAC + PLUGIN_REGISTER(PRF, openssl_hmac_prf_create), +#ifndef OPENSSL_NO_MD5 + PLUGIN_PROVIDE(PRF, PRF_HMAC_MD5), +#endif +#ifndef OPENSSL_NO_SHA1 + PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA1), +#endif +#ifndef OPENSSL_NO_SHA256 + PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_256), +#endif +#ifndef OPENSSL_NO_SHA512 + PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_384), + PLUGIN_PROVIDE(PRF, PRF_HMAC_SHA2_512), +#endif + PLUGIN_REGISTER(SIGNER, openssl_hmac_signer_create), +#ifndef OPENSSL_NO_MD5 + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_MD5_96), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_MD5_128), +#endif +#ifndef OPENSSL_NO_SHA1 + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_96), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_128), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA1_160), +#endif +#ifndef OPENSSL_NO_SHA256 + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_128), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_256_256), +#endif +#ifndef OPENSSL_NO_SHA512 + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_192), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_384_384), + PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256), +#endif +#endif /* OPENSSL_NO_HMAC */ #ifndef OPENSSL_NO_DH /* MODP DH groups */ PLUGIN_REGISTER(DH, openssl_diffie_hellman_create), @@ -284,7 +327,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PRIVKEY, KEY_ANY), PLUGIN_REGISTER(PRIVKEY_GEN, openssl_rsa_private_key_gen, FALSE), PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA), - PLUGIN_REGISTER(PUBKEY, openssl_rsa_public_key_load, FALSE), + PLUGIN_REGISTER(PUBKEY, openssl_rsa_public_key_load, TRUE), PLUGIN_PROVIDE(PUBKEY, KEY_RSA), PLUGIN_REGISTER(PUBKEY, openssl_rsa_public_key_load, TRUE), PLUGIN_PROVIDE(PUBKEY, KEY_ANY), @@ -317,6 +360,9 @@ METHOD(plugin_t, get_features, int, /* certificate/CRL loading */ PLUGIN_REGISTER(CERT_DECODE, openssl_x509_load, TRUE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509), + PLUGIN_SDEPEND(PUBKEY, KEY_RSA), + PLUGIN_SDEPEND(PUBKEY, KEY_ECDSA), + PLUGIN_SDEPEND(PUBKEY, KEY_DSA), PLUGIN_REGISTER(CERT_DECODE, openssl_crl_load, TRUE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_CRL), #ifndef OPENSSL_NO_ECDH @@ -360,6 +406,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_ECDSA_521), #endif #endif /* OPENSSL_NO_ECDSA */ + PLUGIN_REGISTER(RNG, openssl_rng_create), + PLUGIN_PROVIDE(RNG, RNG_STRONG), + PLUGIN_PROVIDE(RNG, RNG_WEAK), }; *features = f; return countof(f); diff --git a/src/libstrongswan/plugins/openssl/openssl_rng.c b/src/libstrongswan/plugins/openssl/openssl_rng.c new file mode 100644 index 000000000..c83244f60 --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_rng.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Aleksandr Grinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "openssl_rng.h" + +typedef struct private_openssl_rng_t private_openssl_rng_t; + +/** + * Private data of openssl_rng_t + */ +struct private_openssl_rng_t { + + /** + * Public part of this class. + */ + openssl_rng_t public; + + /** + * Quality of randomness + */ + rng_quality_t quality; +}; + +METHOD(rng_t, get_bytes, bool, + private_openssl_rng_t *this, size_t bytes, u_int8_t *buffer) +{ + u_int32_t ret; + + if (this->quality == RNG_STRONG) + { + ret = RAND_bytes((char*)buffer, bytes); + } + else + { + ret = RAND_pseudo_bytes((char*)buffer, bytes); + } + return ret != 0; +} + +METHOD(rng_t, allocate_bytes, bool, + private_openssl_rng_t *this, size_t bytes, chunk_t *chunk) +{ + *chunk = chunk_alloc(bytes); + if (!get_bytes(this, chunk->len, chunk->ptr)) + { + chunk_free(chunk); + return FALSE; + } + return TRUE; +} + +METHOD(rng_t, destroy, void, + private_openssl_rng_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +openssl_rng_t *openssl_rng_create(rng_quality_t quality) +{ + private_openssl_rng_t *this; + + INIT(this, + .public = { + .rng = { + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .destroy = _destroy, + }, + }, + .quality = quality, + ); + + return &this->public; +} diff --git a/src/libstrongswan/plugins/openssl/openssl_rng.h b/src/libstrongswan/plugins/openssl/openssl_rng.h new file mode 100644 index 000000000..a4596563a --- /dev/null +++ b/src/libstrongswan/plugins/openssl/openssl_rng.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 Aleksandr Grinberg + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * @defgroup openssl_rng openssl_rng + * @{ @ingroup openssl_p + */ + +#ifndef OPENSSL_RNG_H_ +#define OPENSSL_RNG_H_ + +#include + +typedef struct openssl_rng_t openssl_rng_t; + +/** + * Implementation of random number using OpenSSL. + */ +struct openssl_rng_t { + + /** + * Implements rng_t interface. + */ + rng_t rng; +}; + +/** + * Constructor to create openssl_rng_t. + * + * @param quality quality of randomness + * @return openssl_rng_t + */ +openssl_rng_t *openssl_rng_create(rng_quality_t quality); + +#endif /** OPENSSL_RNG_H_ @}*/ diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index d1afd94cc..98cd700bf 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -475,7 +475,8 @@ static bool login(ENGINE *engine, chunk_t keyid) { found = TRUE; key = shared->get_key(shared); - if (snprintf(pin, sizeof(pin), "%.*s", key.len, key.ptr) >= sizeof(pin)) + if (snprintf(pin, sizeof(pin), + "%.*s", (int)key.len, key.ptr) >= sizeof(pin)) { continue; } diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index a24bae5d6..5872a8159 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -217,13 +217,13 @@ bool openssl_rsa_fingerprint(RSA *rsa, cred_encoding_type_t type, chunk_t *fp) return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, key, fp)) { DBG1(DBG_LIB, "SHA1 hash algorithm not supported, fingerprinting failed"); + DESTROY_IF(hasher); free(key.ptr); return FALSE; } - hasher->allocate_hash(hasher, key, fp); free(key.ptr); hasher->destroy(hasher); lib->encoding->cache(lib->encoding, type, rsa, *fp); diff --git a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c index 20f2fa984..8501e2cd4 100644 --- a/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c +++ b/src/libstrongswan/plugins/openssl/openssl_sha1_prf.c @@ -35,7 +35,7 @@ struct private_openssl_sha1_prf_t { SHA_CTX ctx; }; -METHOD(prf_t, get_bytes, void, +METHOD(prf_t, get_bytes, bool, private_openssl_sha1_prf_t *this, chunk_t seed, u_int8_t *bytes) { SHA1_Update(&this->ctx, seed.ptr, seed.len); @@ -50,6 +50,8 @@ METHOD(prf_t, get_bytes, void, hash[3] = htonl(this->ctx.h3); hash[4] = htonl(this->ctx.h4); } + + return TRUE; } METHOD(prf_t, get_block_size, size_t, @@ -58,18 +60,15 @@ METHOD(prf_t, get_block_size, size_t, return HASH_SIZE_SHA1; } -METHOD(prf_t, allocate_bytes, void, +METHOD(prf_t, allocate_bytes, bool, private_openssl_sha1_prf_t *this, chunk_t seed, chunk_t *chunk) { if (chunk) { *chunk = chunk_alloc(HASH_SIZE_SHA1); - get_bytes(this, seed, chunk->ptr); - } - else - { - get_bytes(this, seed, NULL); + return get_bytes(this, seed, chunk->ptr); } + return get_bytes(this, seed, NULL); } METHOD(prf_t, get_key_size, size_t, @@ -78,11 +77,15 @@ METHOD(prf_t, get_key_size, size_t, return HASH_SIZE_SHA1; } -METHOD(prf_t, set_key, void, +METHOD(prf_t, set_key, bool, private_openssl_sha1_prf_t *this, chunk_t key) { SHA1_Init(&this->ctx); + if (key.len % 4) + { + return FALSE; + } if (key.len >= 4) { this->ctx.h0 ^= untoh32(key.ptr); @@ -103,6 +106,7 @@ METHOD(prf_t, set_key, void, { this->ctx.h4 ^= untoh32(key.ptr + 16); } + return TRUE; } METHOD(prf_t, destroy, void, diff --git a/src/libstrongswan/plugins/openssl/openssl_x509.c b/src/libstrongswan/plugins/openssl/openssl_x509.c index 5caf5182c..e85c5cc90 100644 --- a/src/libstrongswan/plugins/openssl/openssl_x509.c +++ b/src/libstrongswan/plugins/openssl/openssl_x509.c @@ -350,7 +350,8 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_openssl_x509_t *this, certificate_t *issuer) + private_openssl_x509_t *this, certificate_t *issuer, + signature_scheme_t *scheme) { public_key_t *key; bool valid; @@ -393,6 +394,10 @@ METHOD(certificate_t, issued_by, bool, openssl_asn1_str2chunk(this->x509->signature)); free(tbs.ptr); key->destroy(key); + if (valid && scheme) + { + *scheme = this->scheme; + } return valid; } @@ -968,14 +973,14 @@ static bool parse_certificate(private_openssl_x509_t *this) parse_extKeyUsage(this); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, this->encoding, &this->hash)) { + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, this->encoding, &this->hash); hasher->destroy(hasher); - if (issued_by(this, &this->public.x509.interface)) + if (issued_by(this, &this->public.x509.interface, NULL)) { this->flags |= X509_SELF_SIGNED; } diff --git a/src/libstrongswan/plugins/padlock/Makefile.in b/src/libstrongswan/plugins/padlock/Makefile.in index 6ff607456..5a559eadf 100644 --- a/src/libstrongswan/plugins/padlock/Makefile.in +++ b/src/libstrongswan/plugins/padlock/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_padlock_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_padlock_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_padlock_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/padlock/padlock_aes_crypter.c b/src/libstrongswan/plugins/padlock/padlock_aes_crypter.c index 119de86aa..b5060de0a 100644 --- a/src/libstrongswan/plugins/padlock/padlock_aes_crypter.c +++ b/src/libstrongswan/plugins/padlock/padlock_aes_crypter.c @@ -109,16 +109,18 @@ static void crypt(private_padlock_aes_crypter_t *this, char *iv, memwipe(key_aligned, sizeof(key_aligned)); } -METHOD(crypter_t, decrypt, void, +METHOD(crypter_t, decrypt, bool, private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { crypt(this, iv.ptr, data, dst, TRUE); + return TRUE; } -METHOD(crypter_t, encrypt, void, +METHOD(crypter_t, encrypt, bool, private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst) { crypt(this, iv.ptr, data, dst, FALSE); + return TRUE; } METHOD(crypter_t, get_block_size, size_t, @@ -139,10 +141,11 @@ METHOD(crypter_t, get_key_size, size_t, return this->key.len; } -METHOD(crypter_t, set_key, void, +METHOD(crypter_t, set_key, bool, private_padlock_aes_crypter_t *this, chunk_t key) { memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len)); + return TRUE; } METHOD(crypter_t, destroy, void, diff --git a/src/libstrongswan/plugins/padlock/padlock_rng.c b/src/libstrongswan/plugins/padlock/padlock_rng.c index 3d805df9d..517914ab5 100644 --- a/src/libstrongswan/plugins/padlock/padlock_rng.c +++ b/src/libstrongswan/plugins/padlock/padlock_rng.c @@ -69,7 +69,7 @@ static void rng(char *buf, int len, int quality) } } -METHOD(rng_t, allocate_bytes, void, +METHOD(rng_t, allocate_bytes, bool, private_padlock_rng_t *this, size_t bytes, chunk_t *chunk) { chunk->len = bytes; @@ -77,9 +77,10 @@ METHOD(rng_t, allocate_bytes, void, chunk->ptr = malloc(bytes + 7); rng(chunk->ptr, chunk->len, this->quality); + return TRUE; } -METHOD(rng_t, get_bytes, void, +METHOD(rng_t, get_bytes, bool, private_padlock_rng_t *this, size_t bytes, u_int8_t *buffer) { chunk_t chunk; @@ -88,6 +89,7 @@ METHOD(rng_t, get_bytes, void, allocate_bytes(this, bytes, &chunk); memcpy(buffer, chunk.ptr, bytes); chunk_clear(&chunk); + return TRUE; } METHOD(rng_t, destroy, void, diff --git a/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.c b/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.c index 66a077353..4489b902a 100644 --- a/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.c +++ b/src/libstrongswan/plugins/padlock/padlock_sha1_hasher.c @@ -83,13 +83,14 @@ static void append_data(private_padlock_sha1_hasher_t *this, chunk_t data) this->data.len += data.len; } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_padlock_sha1_hasher_t *this) { chunk_free(&this->data); + return TRUE; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_padlock_sha1_hasher_t *this, chunk_t chunk, u_int8_t *hash) { if (hash) @@ -109,20 +110,18 @@ METHOD(hasher_t, get_hash, void, { append_data(this, chunk); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_padlock_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) { if (hash) { *hash = chunk_alloc(HASH_SIZE_SHA1); - get_hash(this, chunk, hash->ptr); - } - else - { - get_hash(this, chunk, NULL); + return get_hash(this, chunk, hash->ptr); } + return get_hash(this, chunk, NULL); } METHOD(hasher_t, get_hash_size, size_t, diff --git a/src/libstrongswan/plugins/pem/Makefile.in b/src/libstrongswan/plugins/pem/Makefile.in index 98c196ef4..7988d1e74 100644 --- a/src/libstrongswan/plugins/pem/Makefile.in +++ b/src/libstrongswan/plugins/pem/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_pem_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_pem_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_pem_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pem_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pem/pem_builder.c b/src/libstrongswan/plugins/pem/pem_builder.c index c5d96be47..9b9777031 100644 --- a/src/libstrongswan/plugins/pem/pem_builder.c +++ b/src/libstrongswan/plugins/pem/pem_builder.c @@ -104,15 +104,21 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, } hash.len = hasher->get_hash_size(hasher); hash.ptr = alloca(hash.len); - hasher->get_hash(hasher, passphrase, NULL); - hasher->get_hash(hasher, salt, hash.ptr); + if (!hasher->get_hash(hasher, passphrase, NULL) || + !hasher->get_hash(hasher, salt, hash.ptr)) + { + return FAILED; + } memcpy(key.ptr, hash.ptr, hash.len); if (key.len > hash.len) { - hasher->get_hash(hasher, hash, NULL); - hasher->get_hash(hasher, passphrase, NULL); - hasher->get_hash(hasher, salt, hash.ptr); + if (!hasher->get_hash(hasher, hash, NULL) || + !hasher->get_hash(hasher, passphrase, NULL) || + !hasher->get_hash(hasher, salt, hash.ptr)) + { + return FAILED; + } memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len); } hasher->destroy(hasher); @@ -125,7 +131,6 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, encryption_algorithm_names, alg); return NOT_SUPPORTED; } - crypter->set_key(crypter, key); if (iv.len != crypter->get_iv_size(crypter) || blob->len % crypter->get_block_size(crypter)) @@ -134,7 +139,12 @@ static status_t pem_decrypt(chunk_t *blob, encryption_algorithm_t alg, DBG1(DBG_ASN, " data size is not multiple of block size"); return PARSE_ERROR; } - crypter->decrypt(crypter, *blob, iv, &decrypted); + if (!crypter->set_key(crypter, key) || + !crypter->decrypt(crypter, *blob, iv, &decrypted)) + { + crypter->destroy(crypter); + return FAILED; + } crypter->destroy(crypter); memcpy(blob->ptr, decrypted.ptr, blob->len); chunk_free(&decrypted); @@ -275,7 +285,7 @@ static status_t pem_to_bin(chunk_t *blob, bool *pgp) else { DBG1(DBG_ASN, " encryption algorithm '%.*s'" - " not supported", dek.len, dek.ptr); + " not supported", (int)dek.len, dek.ptr); return NOT_SUPPORTED; } eat_whitespace(&value); diff --git a/src/libstrongswan/plugins/pem/pem_plugin.c b/src/libstrongswan/plugins/pem/pem_plugin.c index fca717a10..d74ab9ee3 100644 --- a/src/libstrongswan/plugins/pem/pem_plugin.c +++ b/src/libstrongswan/plugins/pem/pem_plugin.c @@ -46,46 +46,64 @@ METHOD(plugin_t, get_features, int, /* private key PEM decoding */ PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), PLUGIN_PROVIDE(PRIVKEY, KEY_ANY), - PLUGIN_DEPENDS(HASHER, HASH_MD5), + PLUGIN_DEPENDS(PRIVKEY, KEY_ANY), + PLUGIN_SDEPEND(HASHER, HASH_MD5), PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), PLUGIN_PROVIDE(PRIVKEY, KEY_RSA), - PLUGIN_DEPENDS(HASHER, HASH_MD5), + PLUGIN_DEPENDS(PRIVKEY, KEY_RSA), + PLUGIN_SDEPEND(HASHER, HASH_MD5), PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA), - PLUGIN_DEPENDS(HASHER, HASH_MD5), + PLUGIN_DEPENDS(PRIVKEY, KEY_ECDSA), + PLUGIN_SDEPEND(HASHER, HASH_MD5), PLUGIN_REGISTER(PRIVKEY, pem_private_key_load, FALSE), PLUGIN_PROVIDE(PRIVKEY, KEY_DSA), - PLUGIN_DEPENDS(HASHER, HASH_MD5), + PLUGIN_DEPENDS(PRIVKEY, KEY_DSA), + PLUGIN_SDEPEND(HASHER, HASH_MD5), /* public key PEM decoding */ PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_ANY), + PLUGIN_DEPENDS(PUBKEY, KEY_ANY), PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_RSA), + PLUGIN_DEPENDS(PUBKEY, KEY_RSA), PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_ECDSA), + PLUGIN_DEPENDS(PUBKEY, KEY_ECDSA), PLUGIN_REGISTER(PUBKEY, pem_public_key_load, FALSE), PLUGIN_PROVIDE(PUBKEY, KEY_DSA), + PLUGIN_DEPENDS(PUBKEY, KEY_DSA), /* certificate PEM decoding */ PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_ANY), + PLUGIN_SDEPEND(CERT_DECODE, CERT_X509), + PLUGIN_SDEPEND(CERT_DECODE, CERT_GPG), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_CRL), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_CRL), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_OCSP_REQUEST), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_OCSP_REQUEST), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_OCSP_RESPONSE), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_OCSP_RESPONSE), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509_AC), + PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_AC), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_PKCS10_REQUEST), + PLUGIN_DEPENDS(CERT_DECODE, CERT_PKCS10_REQUEST), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_TRUSTED_PUBKEY), + PLUGIN_DEPENDS(CERT_DECODE, CERT_TRUSTED_PUBKEY), PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), PLUGIN_PROVIDE(CERT_DECODE, CERT_GPG), + PLUGIN_DEPENDS(CERT_DECODE, CERT_GPG), /* pluto specific certificate formats */ PLUGIN_REGISTER(CERT_DECODE, pem_certificate_load, FALSE), diff --git a/src/libstrongswan/plugins/pgp/Makefile.in b/src/libstrongswan/plugins/pgp/Makefile.in index 946424eee..65acdc196 100644 --- a/src/libstrongswan/plugins/pgp/Makefile.in +++ b/src/libstrongswan/plugins/pgp/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_pgp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_pgp_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_pgp_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pgp_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pgp/pgp_cert.c b/src/libstrongswan/plugins/pgp/pgp_cert.c index 70a236855..a99bed2f6 100644 --- a/src/libstrongswan/plugins/pgp/pgp_cert.c +++ b/src/libstrongswan/plugins/pgp/pgp_cert.c @@ -114,7 +114,7 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by,bool, - private_pgp_cert_t *this, certificate_t *issuer) + private_pgp_cert_t *this, certificate_t *issuer, signature_scheme_t *scheme) { /* TODO: check signature blobs for a valid signature */ return FALSE; @@ -321,8 +321,12 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet) DBG1(DBG_ASN, "no SHA-1 hasher available"); return FALSE; } - hasher->allocate_hash(hasher, pubkey_packet_header, NULL); - hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint); + if (!hasher->allocate_hash(hasher, pubkey_packet_header, NULL) || + !hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint)) + { + hasher->destroy(hasher); + return FALSE; + } hasher->destroy(hasher); DBG2(DBG_ASN, "L2 - v4 fingerprint %#B", &this->fingerprint); } diff --git a/src/libstrongswan/plugins/pgp/pgp_encoder.c b/src/libstrongswan/plugins/pgp/pgp_encoder.c index 9043cdb9f..d16d1d71b 100644 --- a/src/libstrongswan/plugins/pgp/pgp_encoder.c +++ b/src/libstrongswan/plugins/pgp/pgp_encoder.c @@ -44,8 +44,12 @@ static bool build_v3_fingerprint(chunk_t *encoding, va_list args) { e = chunk_skip(e, 1); } - hasher->allocate_hash(hasher, n, NULL); - hasher->allocate_hash(hasher, e, encoding); + if (!hasher->allocate_hash(hasher, n, NULL) || + !hasher->allocate_hash(hasher, e, encoding)) + { + hasher->destroy(hasher); + return FALSE; + } hasher->destroy(hasher); return TRUE; } diff --git a/src/libstrongswan/plugins/pkcs1/Makefile.in b/src/libstrongswan/plugins/pkcs1/Makefile.in index f9322a62d..85246f3de 100644 --- a/src/libstrongswan/plugins/pkcs1/Makefile.in +++ b/src/libstrongswan/plugins/pkcs1/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_pkcs1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_pkcs1_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pkcs1_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pkcs1/pkcs1_encoder.c b/src/libstrongswan/plugins/pkcs1/pkcs1_encoder.c index 6957b2ad1..9122e8d8e 100644 --- a/src/libstrongswan/plugins/pkcs1/pkcs1_encoder.c +++ b/src/libstrongswan/plugins/pkcs1/pkcs1_encoder.c @@ -94,14 +94,14 @@ static bool hash_pubkey(chunk_t pubkey, chunk_t *hash) hasher_t *hasher; hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) + if (!hasher || !hasher->allocate_hash(hasher, pubkey, hash)) { + DESTROY_IF(hasher); chunk_free(&pubkey); DBG1(DBG_LIB, "SHA1 hash algorithm not supported, " "fingerprinting failed"); return FALSE; } - hasher->allocate_hash(hasher, pubkey, hash); hasher->destroy(hasher); chunk_free(&pubkey); return TRUE; diff --git a/src/libstrongswan/plugins/pkcs11/Makefile.in b/src/libstrongswan/plugins/pkcs11/Makefile.in index 2ead77f5a..dc0ab1e82 100644 --- a/src/libstrongswan/plugins/pkcs11/Makefile.in +++ b/src/libstrongswan/plugins/pkcs11/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -87,7 +88,7 @@ libstrongswan_pkcs11_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_pkcs11_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pkcs11_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -113,6 +114,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -207,11 +209,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -228,11 +233,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -248,6 +254,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -257,7 +264,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c b/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c index a81ec1147..7536ce1d3 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_creds.c @@ -109,7 +109,8 @@ static void find_certificates(private_pkcs11_creds_t *this, if (cert) { DBG1(DBG_CFG, " loaded %strusted cert '%.*s'", - entry->trusted ? "" : "un", entry->label.len, entry->label.ptr); + entry->trusted ? "" : "un", (int)entry->label.len, + entry->label.ptr); /* trusted certificates are also returned as untrusted */ this->untrusted->insert_last(this->untrusted, cert); if (entry->trusted) @@ -120,7 +121,7 @@ static void find_certificates(private_pkcs11_creds_t *this, else { DBG1(DBG_CFG, " loading cert '%.*s' failed", - entry->label.len, entry->label.ptr); + (int)entry->label.len, entry->label.ptr); } free(entry->value.ptr); free(entry->label.ptr); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c index 069fa98b6..53a2bfca7 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_hasher.c @@ -84,7 +84,7 @@ METHOD(hasher_t, get_hash_size, size_t, /** * Save the Operation state to host memory */ -static void save_state(private_pkcs11_hasher_t *this) +static bool save_state(private_pkcs11_hasher_t *this) { CK_RV rv; @@ -110,20 +110,20 @@ static void save_state(private_pkcs11_hasher_t *this) continue; case CKR_OK: this->have_state = TRUE; - return; + return TRUE; default: break; } break; } DBG1(DBG_CFG, "C_GetOperationState() failed: %N", ck_rv_names, rv); - abort(); + return FALSE; } /** * Load the Operation state from host memory */ -static void load_state(private_pkcs11_hasher_t *this) +static bool load_state(private_pkcs11_hasher_t *this) { CK_RV rv; @@ -132,18 +132,20 @@ static void load_state(private_pkcs11_hasher_t *this) if (rv != CKR_OK) { DBG1(DBG_CFG, "C_SetOperationState() failed: %N", ck_rv_names, rv); - abort(); + return FALSE; } this->have_state = FALSE; + return TRUE; } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_pkcs11_hasher_t *this) { this->have_state = FALSE; + return TRUE; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_pkcs11_hasher_t *this, chunk_t chunk, u_int8_t *hash) { CK_RV rv; @@ -152,7 +154,11 @@ METHOD(hasher_t, get_hash, void, this->mutex->lock(this->mutex); if (this->have_state) { - load_state(this); + if (!load_state(this)) + { + this->mutex->unlock(this->mutex); + return FALSE; + } } else { @@ -160,7 +166,8 @@ METHOD(hasher_t, get_hash, void, if (rv != CKR_OK) { DBG1(DBG_CFG, "C_DigestInit() failed: %N", ck_rv_names, rv); - abort(); + this->mutex->unlock(this->mutex); + return FALSE; } } if (chunk.len) @@ -169,7 +176,8 @@ METHOD(hasher_t, get_hash, void, if (rv != CKR_OK) { DBG1(DBG_CFG, "C_DigestUpdate() failed: %N", ck_rv_names, rv); - abort(); + this->mutex->unlock(this->mutex); + return FALSE; } } if (hash) @@ -180,28 +188,31 @@ METHOD(hasher_t, get_hash, void, if (rv != CKR_OK) { DBG1(DBG_CFG, "C_DigestFinal() failed: %N", ck_rv_names, rv); - abort(); + this->mutex->unlock(this->mutex); + return FALSE; } } else { - save_state(this); + if (!save_state(this)) + { + this->mutex->unlock(this->mutex); + return FALSE; + } } this->mutex->unlock(this->mutex); + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_pkcs11_hasher_t *this, chunk_t chunk, chunk_t *hash) { if (hash) { *hash = chunk_alloc(this->size); - get_hash(this, chunk, hash->ptr); - } - else - { - get_hash(this, chunk, NULL); + return get_hash(this, chunk, hash->ptr); } + return get_hash(this, chunk, NULL); } METHOD(hasher_t, destroy, void, diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c b/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c index 5b321b26e..83c383671 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_manager.c @@ -61,8 +61,6 @@ typedef struct { char *path; /* loaded library */ pkcs11_library_t *lib; - /* event dispatcher job */ - callback_job_t *job; } lib_entry_t; /** @@ -70,10 +68,6 @@ typedef struct { */ static void lib_entry_destroy(lib_entry_t *entry) { - if (entry->job) - { - entry->job->cancel(entry->job); - } entry->lib->destroy(entry->lib); free(entry); } @@ -201,14 +195,6 @@ static job_requeue_t dispatch_slot_events(lib_entry_t *entry) return JOB_REQUEUE_DIRECT; } -/** - * End dispatching, unset job - */ -static void end_dispatch(lib_entry_t *entry) -{ - entry->job = NULL; -} - /** * Get the slot list of a library */ @@ -384,9 +370,9 @@ pkcs11_manager_t *pkcs11_manager_create(pkcs11_manager_token_event_t cb, while (enumerator->enumerate(enumerator, &entry)) { query_slots(entry); - entry->job = callback_job_create_with_prio((void*)dispatch_slot_events, - entry, (void*)end_dispatch, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)entry->job); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio((void*)dispatch_slot_events, + entry, NULL, (void*)return_false, JOB_PRIO_CRITICAL)); } enumerator->destroy(enumerator); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index b616abc38..f7f7d3f79 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -266,13 +266,15 @@ METHOD(private_key_t, sign, bool, } if (hash_alg != HASH_UNKNOWN) { - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - if (!hasher) + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) { + DESTROY_IF(hasher); this->lib->f->C_CloseSession(session); return FALSE; } - hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); data = hash; } diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index d4ec9235d..f0d7093db 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -235,13 +235,15 @@ METHOD(public_key_t, verify, bool, } if (hash_alg != HASH_UNKNOWN) { - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - if (!hasher) + hasher_t *hasher; + + hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) { + DESTROY_IF(hasher); this->lib->f->C_CloseSession(session); return FALSE; } - hasher->allocate_hash(hasher, data, &hash); hasher->destroy(hasher); data = hash; } @@ -374,12 +376,12 @@ static bool fingerprint_ecdsa(private_pkcs11_public_key_t *this, return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, asn1, fp)) { + DESTROY_IF(hasher); chunk_clear(&asn1); return FALSE; } - hasher->allocate_hash(hasher, asn1, fp); hasher->destroy(hasher); chunk_clear(&asn1); lib->encoding->cache(lib->encoding, type, this, *fp); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c b/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c index 45cf0b7c2..20e4b6f76 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_rng.c @@ -43,7 +43,7 @@ struct private_pkcs11_rng_t { }; -METHOD(rng_t, get_bytes, void, +METHOD(rng_t, get_bytes, bool, private_pkcs11_rng_t *this, size_t bytes, u_int8_t *buffer) { CK_RV rv; @@ -51,15 +51,21 @@ METHOD(rng_t, get_bytes, void, if (rv != CKR_OK) { DBG1(DBG_CFG, "C_GenerateRandom() failed: %N", ck_rv_names, rv); - abort(); + return FALSE; } + return TRUE; } -METHOD(rng_t, allocate_bytes, void, +METHOD(rng_t, allocate_bytes, bool, private_pkcs11_rng_t *this, size_t bytes, chunk_t *chunk) { *chunk = chunk_alloc(bytes); - get_bytes(this, chunk->len, chunk->ptr); + if (!get_bytes(this, chunk->len, chunk->ptr)) + { + chunk_clear(chunk); + return FALSE; + } + return TRUE; } METHOD(rng_t, destroy, void, diff --git a/src/libstrongswan/plugins/pkcs8/Makefile.in b/src/libstrongswan/plugins/pkcs8/Makefile.in index 2b9c6cf95..60d7ae643 100644 --- a/src/libstrongswan/plugins/pkcs8/Makefile.in +++ b/src/libstrongswan/plugins/pkcs8/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_pkcs8_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_pkcs8_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pkcs8_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c index 346240ae1..a501423b1 100644 --- a/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c +++ b/src/libstrongswan/plugins/pkcs8/pkcs8_builder.c @@ -126,7 +126,7 @@ static bool verify_padding(chunk_t *blob) /** * Prototype for key derivation functions. */ -typedef void (*kdf_t)(void *generator, chunk_t password, chunk_t salt, +typedef bool (*kdf_t)(void *generator, chunk_t password, chunk_t salt, u_int64_t iterations, chunk_t key); /** @@ -164,10 +164,15 @@ static private_key_t *decrypt_private_key(chunk_t blob, { chunk_t decrypted; - kdf(generator, shared->get_key(shared), salt, iterations, keymat); - - crypter->set_key(crypter, key); - crypter->decrypt(crypter, blob, iv, &decrypted); + if (!kdf(generator, shared->get_key(shared), salt, iterations, keymat)) + { + continue; + } + if (!crypter->set_key(crypter, key) || + !crypter->decrypt(crypter, blob, iv, &decrypted)) + { + continue; + } if (verify_padding(&decrypted)) { private_key = parse_private_key(decrypted); @@ -188,34 +193,44 @@ static private_key_t *decrypt_private_key(chunk_t blob, /** * Function F of PBKDF2 */ -static void pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed, +static bool pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed, u_int64_t iterations) { chunk_t u; u_int64_t i; u = chunk_alloca(prf->get_block_size(prf)); - prf->get_bytes(prf, seed, u.ptr); + if (!prf->get_bytes(prf, seed, u.ptr)) + { + return FALSE; + } memcpy(block.ptr, u.ptr, block.len); for (i = 1; i < iterations; i++) { - prf->get_bytes(prf, u, u.ptr); + if (!prf->get_bytes(prf, u, u.ptr)) + { + return FALSE; + } memxor(block.ptr, u.ptr, block.len); } + return TRUE; } /** * PBKDF2 key derivation function */ -static void pbkdf2(prf_t *prf, chunk_t password, chunk_t salt, +static bool pbkdf2(prf_t *prf, chunk_t password, chunk_t salt, u_int64_t iterations, chunk_t key) { chunk_t keymat, block, seed; size_t blocks; u_int32_t i = 0, *ni; - prf->set_key(prf, password); + if (!prf->set_key(prf, password)) + { + return FALSE; + } block.len = prf->get_block_size(prf); blocks = (key.len - 1) / block.len + 1; @@ -228,10 +243,15 @@ static void pbkdf2(prf_t *prf, chunk_t password, chunk_t salt, { *ni = htonl(i + 1); block.ptr = keymat.ptr + (i * block.len); - pbkdf2_f(block, prf, seed, iterations); + if (!pbkdf2_f(block, prf, seed, iterations)) + { + return FALSE; + } } memcpy(key.ptr, keymat.ptr, key.len); + + return TRUE; } /** @@ -266,22 +286,30 @@ static private_key_t *decrypt_private_key_pbes2(chunk_t blob, /** * PBKDF1 key derivation function */ -static void pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt, +static bool pbkdf1(hasher_t *hasher, chunk_t password, chunk_t salt, u_int64_t iterations, chunk_t key) { chunk_t hash; u_int64_t i; hash = chunk_alloca(hasher->get_hash_size(hasher)); - hasher->get_hash(hasher, password, NULL); - hasher->get_hash(hasher, salt, hash.ptr); + if (!hasher->get_hash(hasher, password, NULL) || + !hasher->get_hash(hasher, salt, hash.ptr)) + { + return FALSE; + } for (i = 1; i < iterations; i++) { - hasher->get_hash(hasher, hash, hash.ptr); + if (!hasher->get_hash(hasher, hash, hash.ptr)) + { + return FALSE; + } } memcpy(key.ptr, hash.ptr, key.len); + + return TRUE; } /** @@ -535,7 +563,7 @@ static const asn1Object_t encryptedPKIObjects[] = { static private_key_t *parse_encrypted_private_key(chunk_t blob) { asn1_parser_t *parser; - chunk_t object, params, salt, iv; + chunk_t object, params, salt = chunk_empty, iv = chunk_empty; u_int64_t iterations = 0; int objectID; encryption_algorithm_t encr = ENCR_UNDEFINED; diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index 2a97205bb..6e043878c 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2011 Martin Willi * Copyright (C) 2011 revosec AG * @@ -29,6 +32,7 @@ ENUM(plugin_feature_names, FEATURE_NONE, FEATURE_CUSTOM, "PRF", "DH", "RNG", + "NONCE_GEN", "PRIVKEY", "PRIVKEY_GEN", "PRIVKEY_SIGN", @@ -40,11 +44,63 @@ ENUM(plugin_feature_names, FEATURE_NONE, FEATURE_CUSTOM, "CERT_ENCODE", "EAP_SERVER", "EAP_CLIENT", + "XAUTH_SERVER", + "XAUTH_CLIENT", "DATABASE", "FETCHER", "CUSTOM", ); +/** + * See header. + */ +u_int32_t plugin_feature_hash(plugin_feature_t *feature) +{ + chunk_t data; + + switch (feature->type) + { + case FEATURE_NONE: + case FEATURE_RNG: + case FEATURE_NONCE_GEN: + case FEATURE_DATABASE: + case FEATURE_FETCHER: + /* put these special cases in their (type-specific) buckets */ + data = chunk_empty; + break; + case FEATURE_CRYPTER: + case FEATURE_AEAD: + case FEATURE_SIGNER: + case FEATURE_HASHER: + case FEATURE_PRF: + case FEATURE_DH: + case FEATURE_PRIVKEY: + case FEATURE_PRIVKEY_GEN: + case FEATURE_PUBKEY: + case FEATURE_PRIVKEY_SIGN: + case FEATURE_PUBKEY_VERIFY: + case FEATURE_PRIVKEY_DECRYPT: + case FEATURE_PUBKEY_ENCRYPT: + case FEATURE_CERT_DECODE: + case FEATURE_CERT_ENCODE: + case FEATURE_EAP_SERVER: + case FEATURE_EAP_PEER: + data = chunk_from_thing(feature->arg); + break; + case FEATURE_CUSTOM: + data = chunk_create(feature->arg.custom, + strlen(feature->arg.custom)); + break; + case FEATURE_XAUTH_SERVER: + case FEATURE_XAUTH_PEER: + data = chunk_create(feature->arg.xauth, + strlen(feature->arg.xauth)); + break; + } + return chunk_hash_inc(chunk_from_thing(feature->type), + chunk_hash(data)); +} + /** * See header. */ @@ -72,6 +128,8 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b) return a->arg.dh_group == b->arg.dh_group; case FEATURE_RNG: return a->arg.rng_quality <= b->arg.rng_quality; + case FEATURE_NONCE_GEN: + return TRUE; case FEATURE_PRIVKEY: case FEATURE_PRIVKEY_GEN: case FEATURE_PUBKEY: @@ -96,6 +154,9 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b) streq(a->arg.fetcher, b->arg.fetcher); case FEATURE_CUSTOM: return streq(a->arg.custom, b->arg.custom); + case FEATURE_XAUTH_SERVER: + case FEATURE_XAUTH_PEER: + return streq(a->arg.xauth, b->arg.xauth); } } return FALSE; @@ -167,6 +228,12 @@ char* plugin_feature_get_string(plugin_feature_t *feature) return str; } break; + case FEATURE_NONCE_GEN: + if (asprintf(&str, "%N", plugin_feature_names, feature->type) > 0) + { + return str; + } + break; case FEATURE_PRIVKEY: case FEATURE_PRIVKEY_GEN: case FEATURE_PUBKEY: @@ -229,6 +296,14 @@ char* plugin_feature_get_string(plugin_feature_t *feature) return str; } break; + case FEATURE_XAUTH_SERVER: + case FEATURE_XAUTH_PEER: + if (asprintf(&str, "%N:%s", plugin_feature_names, feature->type, + feature->arg.xauth) > 0) + { + return str; + } + break; } if (!str) { @@ -251,7 +326,8 @@ bool plugin_feature_load(plugin_t *plugin, plugin_feature_t *feature, } if (reg->kind == FEATURE_CALLBACK) { - if (reg->arg.cb.f(plugin, feature, TRUE, reg->arg.cb.data)) + if (!reg->arg.cb.f || + reg->arg.cb.f(plugin, feature, TRUE, reg->arg.cb.data)) { return TRUE; } @@ -288,6 +364,10 @@ bool plugin_feature_load(plugin_t *plugin, plugin_feature_t *feature, lib->crypto->add_rng(lib->crypto, feature->arg.rng_quality, name, reg->arg.reg.f); break; + case FEATURE_NONCE_GEN: + lib->crypto->add_nonce_gen(lib->crypto, + name, reg->arg.reg.f); + break; case FEATURE_PRIVKEY: case FEATURE_PRIVKEY_GEN: lib->creds->add_builder(lib->creds, CRED_PRIVATE_KEY, @@ -330,7 +410,8 @@ bool plugin_feature_unload(plugin_t *plugin, plugin_feature_t *feature, } if (reg->kind == FEATURE_CALLBACK) { - if (reg->arg.cb.f(plugin, feature, FALSE, reg->arg.cb.data)) + if (!reg->arg.cb.f || + reg->arg.cb.f(plugin, feature, FALSE, reg->arg.cb.data)) { return TRUE; } @@ -359,6 +440,9 @@ bool plugin_feature_unload(plugin_t *plugin, plugin_feature_t *feature, case FEATURE_RNG: lib->crypto->remove_rng(lib->crypto, reg->arg.reg.f); break; + case FEATURE_NONCE_GEN: + lib->crypto->remove_nonce_gen(lib->crypto, reg->arg.reg.f); + break; case FEATURE_PRIVKEY: case FEATURE_PRIVKEY_GEN: lib->creds->remove_builder(lib->creds, reg->arg.reg.f); diff --git a/src/libstrongswan/plugins/plugin_feature.h b/src/libstrongswan/plugins/plugin_feature.h index b1500feba..90f8a948a 100644 --- a/src/libstrongswan/plugins/plugin_feature.h +++ b/src/libstrongswan/plugins/plugin_feature.h @@ -1,4 +1,7 @@ /* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2011 Martin Willi * Copyright (C) 2011 revosec AG * @@ -48,17 +51,19 @@ typedef bool (*plugin_feature_callback_t)(plugin_t *plugin, * features provided by the plugin, hard (DEPENDS) or soft (SDEPEND) dependency * specified is related to the previously defined PROVIDE feature. * If a plugin feature requires to hook in functionality into the library - * or a daemon, it can use REGISTER or CALLBACK entries. Each PROVIDED feature + * or a daemon, it can use REGISTER or CALLBACK entries. Each PROVIDE feature * uses the REGISTER/CALLBACK entry defined previously. The REGISTER entry * defines a common feature registration function directly passed to the * associated manager or factory (crypto/credential factory etc.). A callback * function is more generic allows the loader to invoke a callback to do - * the registration. + * the registration. PROVIDE features that do not use a registration or callback + * function must be listed before any REGISTER/CALLBACK entry, or use the NOOP + * helper macro. * - * To conviently create feature lists, use the four macros PLUGIN_REGISTER, - * PLUGIN_CALLBACK, PLUGIN_PROVIDE, PLUGIN_DEPENDS and PLUGIN_SDEPEND. Use - * identation to show how the registration functions and dependencies are - * related to a provided feature, such as: + * To conveniently create feature lists, use the macros PLUGIN_REGISTER, + * PLUGIN_CALLBACK, PLUGIN_NOOP, PLUGIN_PROVIDE, PLUGIN_DEPENDS and + * PLUGIN_SDEPEND. Use indentation to show how the registration functions + * and dependencies are related to a provided feature, such as: * * @verbatim // two features, one with two dependencies, both use a callback to register @@ -72,7 +77,8 @@ typedef bool (*plugin_feature_callback_t)(plugin_t *plugin, PLUGIN_PROVIDE(...), PLUGIN_DEPENDS(...), // feature that does not use a registration function - PLUGIN_PROVIDE(...), + PLUGIN_NOOP, + PLUGIN_PROVIDE(...), @endverbatim */ struct plugin_feature_t { @@ -107,6 +113,8 @@ struct plugin_feature_t { FEATURE_DH, /** rng_t */ FEATURE_RNG, + /** nonce_gen_t */ + FEATURE_NONCE_GEN, /** generic private key support */ FEATURE_PRIVKEY, /** generating new private keys */ @@ -129,6 +137,10 @@ struct plugin_feature_t { FEATURE_EAP_SERVER, /** EAP peer implementation */ FEATURE_EAP_PEER, + /** XAuth server implementation */ + FEATURE_XAUTH_SERVER, + /** XAuth peer implementation */ + FEATURE_XAUTH_PEER, /** database_t */ FEATURE_DATABASE, /** fetcher_t */ @@ -182,6 +194,8 @@ struct plugin_feature_t { char *fetcher; /** FEATURE_CUSTOM */ char *custom; + /** FEATURE_XAUTH_SERVER/CLIENT */ + char *xauth; /** FEATURE_REGISTER */ struct { @@ -220,6 +234,11 @@ struct plugin_feature_t { */ #define PLUGIN_CALLBACK(cb, data) _PLUGIN_FEATURE_CALLBACK(cb, data) +/** + * The upcoming features use neither a callback nor a register function. + */ +#define PLUGIN_NOOP _PLUGIN_FEATURE_CALLBACK(NULL, NULL) + /** * Define a feature the plugin provides. * @@ -252,6 +271,7 @@ struct plugin_feature_t { #define _PLUGIN_FEATURE_PRF(kind, alg) __PLUGIN_FEATURE(kind, PRF, .prf = alg) #define _PLUGIN_FEATURE_DH(kind, group) __PLUGIN_FEATURE(kind, DH, .dh_group = group) #define _PLUGIN_FEATURE_RNG(kind, quality) __PLUGIN_FEATURE(kind, RNG, .rng_quality = quality) +#define _PLUGIN_FEATURE_NONCE_GEN(kind, ...) __PLUGIN_FEATURE(kind, NONCE_GEN, .custom = NULL) #define _PLUGIN_FEATURE_PRIVKEY(kind, type) __PLUGIN_FEATURE(kind, PRIVKEY, .privkey = type) #define _PLUGIN_FEATURE_PRIVKEY_GEN(kind, type) __PLUGIN_FEATURE(kind, PRIVKEY_GEN, .privkey_gen = type) #define _PLUGIN_FEATURE_PRIVKEY_SIGN(kind, scheme) __PLUGIN_FEATURE(kind, PRIVKEY_SIGN, .privkey_sign = scheme) @@ -266,6 +286,8 @@ struct plugin_feature_t { #define _PLUGIN_FEATURE_DATABASE(kind, type) __PLUGIN_FEATURE(kind, DATABASE, .database = type) #define _PLUGIN_FEATURE_FETCHER(kind, type) __PLUGIN_FEATURE(kind, FETCHER, .fetcher = type) #define _PLUGIN_FEATURE_CUSTOM(kind, name) __PLUGIN_FEATURE(kind, CUSTOM, .custom = name) +#define _PLUGIN_FEATURE_XAUTH_SERVER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_SERVER, .xauth = name) +#define _PLUGIN_FEATURE_XAUTH_PEER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_PEER, .xauth = name) #define __PLUGIN_FEATURE_REGISTER(type, _f) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg.f = _f } #define __PLUGIN_FEATURE_REGISTER_BUILDER(type, _f, _final) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg = {.f = _f, .final = _final, }} @@ -276,6 +298,7 @@ struct plugin_feature_t { #define _PLUGIN_FEATURE_REGISTER_PRF(type, f) __PLUGIN_FEATURE_REGISTER(type, f) #define _PLUGIN_FEATURE_REGISTER_DH(type, f) __PLUGIN_FEATURE_REGISTER(type, f) #define _PLUGIN_FEATURE_REGISTER_RNG(type, f) __PLUGIN_FEATURE_REGISTER(type, f) +#define _PLUGIN_FEATURE_REGISTER_NONCE_GEN(type, f) __PLUGIN_FEATURE_REGISTER(type, f) #define _PLUGIN_FEATURE_REGISTER_PRIVKEY(type, f, final) __PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final) #define _PLUGIN_FEATURE_REGISTER_PRIVKEY_GEN(type, f, final)__PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final) #define _PLUGIN_FEATURE_REGISTER_PUBKEY(type, f, final) __PLUGIN_FEATURE_REGISTER_BUILDER(type, f, final) @@ -291,6 +314,18 @@ struct plugin_feature_t { */ extern enum_name_t *plugin_feature_names; +/** + * Calculates a hash value for the given feature. + * + * Since this is intended to be used with the plugin_features_matches function + * the hash is not really unique for all types of features (e.g. RNGs are all + * mapped to the same value because they are loosely matched by said function). + * + * @param feature feature to hash + * @return hash value of the feature + */ +u_int32_t plugin_feature_hash(plugin_feature_t *feature); + /** * Check if feature a matches to feature b. * diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c index f97cbb31f..95a0bfc02 100644 --- a/src/libstrongswan/plugins/plugin_loader.c +++ b/src/libstrongswan/plugins/plugin_loader.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,11 @@ struct private_plugin_loader_t { */ linked_list_t *plugins; + /** + * Hashtable for loaded features, as plugin_feature_t + */ + hashtable_t *loaded_features; + /** * List of names of loaded plugins */ @@ -62,6 +68,11 @@ struct plugin_entry_t { */ plugin_t *plugin; + /** + * TRUE, if the plugin is marked as critical + */ + bool critical; + /** * dlopen handle, if in separate lib */ @@ -93,13 +104,94 @@ static void plugin_entry_destroy(plugin_entry_t *entry) free(entry); } +/** + * Wrapper for static plugin features + */ +typedef struct { + + /** + * Implements plugin_t interface + */ + plugin_t public; + + /** + * Name of the module registering these features + */ + char *name; + + /** + * Static plugin features + */ + plugin_feature_t *features; + + /** + * Number of plugin features + */ + int count; + +} static_features_t; + +METHOD(plugin_t, get_static_name, char*, + static_features_t *this) +{ + return this->name; +} + +METHOD(plugin_t, get_static_features, int, + static_features_t *this, plugin_feature_t *features[]) +{ + *features = this->features; + return this->count; +} + +METHOD(plugin_t, static_destroy, void, + static_features_t *this) +{ + free(this->features); + free(this->name); + free(this); +} + +/** + * Create a wrapper around static plugin features. + */ +static plugin_t *static_features_create(const char *name, + plugin_feature_t features[], int count) +{ + static_features_t *this; + + INIT(this, + .public = { + .get_name = _get_static_name, + .get_features = _get_static_features, + .destroy = _static_destroy, + }, + .name = strdup(name), + .features = calloc(count, sizeof(plugin_feature_t)), + .count = count, + ); + + memcpy(this->features, features, sizeof(plugin_feature_t) * count); + + return &this->public; +} + +/** + * Compare function for hashtable of loaded features. + */ +static bool plugin_feature_equals(plugin_feature_t *a, plugin_feature_t *b) +{ + return a == b; +} + /** * create a plugin * returns: NOT_FOUND, if the constructor was not found * FAILED, if the plugin could not be constructed */ static status_t create_plugin(private_plugin_loader_t *this, void *handle, - char *name, bool integrity, plugin_entry_t **entry) + char *name, bool integrity, bool critical, + plugin_entry_t **entry) { char create[128]; plugin_t *plugin; @@ -135,6 +227,7 @@ static status_t create_plugin(private_plugin_loader_t *this, void *handle, } INIT(*entry, .plugin = plugin, + .critical = critical, .loaded = linked_list_create(), .failed = linked_list_create(), ); @@ -145,19 +238,23 @@ static status_t create_plugin(private_plugin_loader_t *this, void *handle, /** * load a single plugin */ -static bool load_plugin(private_plugin_loader_t *this, char *name, char *file) +static bool load_plugin(private_plugin_loader_t *this, char *name, char *file, + bool critical) { plugin_entry_t *entry; void *handle; - switch (create_plugin(this, RTLD_DEFAULT, name, FALSE, &entry)) + switch (create_plugin(this, RTLD_DEFAULT, name, FALSE, critical, &entry)) { case SUCCESS: this->plugins->insert_last(this->plugins, entry); return TRUE; case NOT_FOUND: - /* try to load the plugin from a file */ - break; + if (file) + { /* try to load the plugin from a file */ + break; + } + /* fall-through */ default: return FALSE; } @@ -176,7 +273,7 @@ static bool load_plugin(private_plugin_loader_t *this, char *name, char *file) DBG1(DBG_LIB, "plugin '%s' failed to load: %s", name, dlerror()); return FALSE; } - if (create_plugin(this, handle, name, TRUE, &entry) != SUCCESS) + if (create_plugin(this, handle, name, TRUE, critical, &entry) != SUCCESS) { dlclose(handle); return FALSE; @@ -294,32 +391,15 @@ static bool dependencies_satisfied(private_plugin_loader_t *this, /* first entry is provided feature, followed by dependencies */ for (i = 1; i < count; i++) { - enumerator_t *entries, *loaded; - plugin_feature_t *feature; - plugin_entry_t *current; - bool found = FALSE; + plugin_feature_t *found; if (features[i].kind != FEATURE_DEPENDS && features[i].kind != FEATURE_SDEPEND) { /* end of dependencies */ break; } - entries = this->plugins->create_enumerator(this->plugins); - while (entries->enumerate(entries, ¤t)) - { - loaded = current->loaded->create_enumerator(current->loaded); - while (loaded->enumerate(loaded, &feature)) - { - if (plugin_feature_matches(&features[i], feature)) - { - found = TRUE; - break; - } - } - loaded->destroy(loaded); - } - entries->destroy(entries); - + found = this->loaded_features->get_match(this->loaded_features, + &features[i], (hashtable_equals_t)plugin_feature_matches); if (!found && (features[i].kind != FEATURE_SDEPEND || soft)) { if (report) @@ -361,7 +441,8 @@ static bool dependency_required(private_plugin_loader_t *this, count = entry->plugin->get_features(entry->plugin, &features); for (i = 0; i < count; i++) { - if (feature_loaded(this, entry, &features[i])) + if (&features[i] != dep && + feature_loaded(this, entry, &features[i])) { while (++i < count && (features[i].kind == FEATURE_DEPENDS || features[i].kind == FEATURE_SDEPEND)) @@ -410,6 +491,8 @@ static int load_features(private_plugin_loader_t *this, bool soft, bool report) { if (plugin_feature_load(entry->plugin, feature, reg)) { + this->loaded_features->put(this->loaded_features, + feature, feature); entry->loaded->insert_last(entry->loaded, feature); loaded++; } @@ -428,6 +511,10 @@ static int load_features(private_plugin_loader_t *this, bool soft, bool report) } feature++; } + if (loaded && !report) + { /* got new feature, restart from beginning of list */ + break; + } } enumerator->destroy(enumerator); return loaded; @@ -451,6 +538,8 @@ static int unload_features(private_plugin_loader_t *this, plugin_entry_t *entry) !dependency_required(this, feature) && plugin_feature_unload(entry->plugin, feature, reg)) { + this->loaded_features->remove(this->loaded_features, + feature); entry->loaded->remove(entry->loaded, feature, NULL); unloaded++; } @@ -467,6 +556,55 @@ static int unload_features(private_plugin_loader_t *this, plugin_entry_t *entry) return unloaded; } +/** + * Check that we have all features loaded for critical plugins + */ +static bool missing_critical_features(private_plugin_loader_t *this) +{ + enumerator_t *enumerator; + plugin_entry_t *entry; + bool critical_failed = FALSE; + + enumerator = this->plugins->create_enumerator(this->plugins); + while (enumerator->enumerate(enumerator, &entry)) + { + if (!entry->plugin->get_features) + { /* feature interface not supported */ + continue; + } + if (entry->critical) + { + plugin_feature_t *feature; + char *name, *provide; + int count, i, failed = 0; + + name = entry->plugin->get_name(entry->plugin); + count = entry->plugin->get_features(entry->plugin, &feature); + for (i = 0; i < count; i++, feature++) + { + if (feature->kind == FEATURE_PROVIDE && + !feature_loaded(this, entry, feature)) + { + provide = plugin_feature_get_string(feature); + DBG2(DBG_LIB, " failed to load %s in critical plugin '%s'", + provide, name); + free(provide); + failed++; + } + } + if (failed) + { + DBG1(DBG_LIB, "failed to load %d feature%s in critical plugin " + "'%s'", failed, failed > 1 ? "s" : "", name); + critical_failed = TRUE; + } + } + } + enumerator->destroy(enumerator); + + return critical_failed; +} + /** * Remove plugins that we were not able to load any features from. */ @@ -491,6 +629,24 @@ static void purge_plugins(private_plugin_loader_t *this) enumerator->destroy(enumerator); } +METHOD(plugin_loader_t, add_static_features, void, + private_plugin_loader_t *this, const char *name, + plugin_feature_t features[], int count, bool critical) +{ + plugin_entry_t *entry; + plugin_t *plugin; + + plugin = static_features_create(name, features, count); + + INIT(entry, + .plugin = plugin, + .critical = critical, + .loaded = linked_list_create(), + .failed = linked_list_create(), + ); + this->plugins->insert_last(this->plugins, entry); +} + METHOD(plugin_loader_t, load_plugins, bool, private_plugin_loader_t *this, char *path, char *list) { @@ -498,16 +654,18 @@ METHOD(plugin_loader_t, load_plugins, bool, char *token; bool critical_failed = FALSE; +#ifdef PLUGINDIR if (path == NULL) { path = PLUGINDIR; } +#endif /* PLUGINDIR */ enumerator = enumerator_create_token(list, " ", " "); while (!critical_failed && enumerator->enumerate(enumerator, &token)) { bool critical = FALSE; - char file[PATH_MAX]; + char buf[PATH_MAX], *file = NULL; int len; token = strdup(token); @@ -522,12 +680,16 @@ METHOD(plugin_loader_t, load_plugins, bool, free(token); continue; } - if (snprintf(file, sizeof(file), "%s/libstrongswan-%s.so", - path, token) >= sizeof(file)) + if (path) { - return FALSE; + if (snprintf(buf, sizeof(buf), "%s/libstrongswan-%s.so", + path, token) >= sizeof(buf)) + { + return FALSE; + } + file = buf; } - if (!load_plugin(this, token, file) && critical) + if (!load_plugin(this, token, file, critical) && critical) { critical_failed = TRUE; DBG1(DBG_LIB, "loading critical plugin '%s' failed", token); @@ -550,6 +712,8 @@ METHOD(plugin_loader_t, load_plugins, bool, } /* report missing dependencies */ load_features(this, FALSE, TRUE); + /* check for unloaded features provided by critical plugins */ + critical_failed = missing_critical_features(this); /* unload plugins that we were not able to load any features for */ purge_plugins(this); } @@ -660,6 +824,7 @@ METHOD(plugin_loader_t, destroy, void, private_plugin_loader_t *this) { unload(this); + this->loaded_features->destroy(this->loaded_features); this->plugins->destroy(this->plugins); free(this->loaded_plugins); free(this); @@ -674,6 +839,7 @@ plugin_loader_t *plugin_loader_create() INIT(this, .public = { + .add_static_features = _add_static_features, .load = _load_plugins, .reload = _reload, .unload = _unload, @@ -682,6 +848,9 @@ plugin_loader_t *plugin_loader_create() .destroy = _destroy, }, .plugins = linked_list_create(), + .loaded_features = hashtable_create( + (hashtable_hash_t)plugin_feature_hash, + (hashtable_equals_t)plugin_feature_equals, 64), ); return &this->public; diff --git a/src/libstrongswan/plugins/plugin_loader.h b/src/libstrongswan/plugins/plugin_loader.h index 7fd07044d..94181dbb6 100644 --- a/src/libstrongswan/plugins/plugin_loader.h +++ b/src/libstrongswan/plugins/plugin_loader.h @@ -26,11 +26,35 @@ typedef struct plugin_loader_t plugin_loader_t; #include +/* to avoid circular references we can't include plugin_feature.h */ +struct plugin_feature_t; + /** * The plugin_loader loads plugins from a directory and initializes them */ struct plugin_loader_t { + /** + * Add static plugin features, not loaded via plugins. + * + * Similar to features provided by plugins they are evaluated during load(), + * and unloaded when unload() is called. + * + * If critical is TRUE load() will fail if any of the added features could + * not be loaded. + * + * @note The name should be unique otherwise a plugin with the same name is + * not loaded. + * + * @param name name of the component adding the features + * @param features array of plugin features + * @param count number of features in the array + * @param critical TRUE if the features are critical + */ + void (*add_static_features) (plugin_loader_t *this, const char *name, + struct plugin_feature_t *features, int count, + bool critical); + /** * Load a list of plugins from a directory. * diff --git a/src/libstrongswan/plugins/pubkey/Makefile.in b/src/libstrongswan/plugins/pubkey/Makefile.in index 0de048791..6680873c2 100644 --- a/src/libstrongswan/plugins/pubkey/Makefile.in +++ b/src/libstrongswan/plugins/pubkey/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_pubkey_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_pubkey_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_pubkey_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/pubkey/pubkey_cert.c b/src/libstrongswan/plugins/pubkey/pubkey_cert.c index 67240fe0c..0304ccb36 100644 --- a/src/libstrongswan/plugins/pubkey/pubkey_cert.c +++ b/src/libstrongswan/plugins/pubkey/pubkey_cert.c @@ -126,8 +126,13 @@ METHOD(certificate_t, equals, bool, } METHOD(certificate_t, issued_by, bool, - private_pubkey_cert_t *this, certificate_t *issuer) + private_pubkey_cert_t *this, certificate_t *issuer, + signature_scheme_t *scheme) { + if (scheme) + { + *scheme = SIGN_UNKNOWN; + } return equals(this, issuer); } diff --git a/src/libstrongswan/plugins/pubkey/pubkey_plugin.c b/src/libstrongswan/plugins/pubkey/pubkey_plugin.c index 92bfc2e63..a898bbfcc 100644 --- a/src/libstrongswan/plugins/pubkey/pubkey_plugin.c +++ b/src/libstrongswan/plugins/pubkey/pubkey_plugin.c @@ -43,6 +43,11 @@ METHOD(plugin_t, get_features, int, static plugin_feature_t f[] = { PLUGIN_REGISTER(CERT_ENCODE, pubkey_cert_wrap, FALSE), PLUGIN_PROVIDE(CERT_ENCODE, CERT_TRUSTED_PUBKEY), + PLUGIN_REGISTER(CERT_DECODE, pubkey_cert_wrap, TRUE), + PLUGIN_PROVIDE(CERT_DECODE, CERT_TRUSTED_PUBKEY), + PLUGIN_SDEPEND(PUBKEY, KEY_RSA), + PLUGIN_SDEPEND(PUBKEY, KEY_ECDSA), + PLUGIN_SDEPEND(PUBKEY, KEY_DSA), }; *features = f; return countof(f); diff --git a/src/libstrongswan/plugins/random/Makefile.in b/src/libstrongswan/plugins/random/Makefile.in index 9b549b071..a393e8049 100644 --- a/src/libstrongswan/plugins/random/Makefile.in +++ b/src/libstrongswan/plugins/random/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_random_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_random_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_random_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/random/random_plugin.c b/src/libstrongswan/plugins/random/random_plugin.c index 7f81e2622..cef20047a 100644 --- a/src/libstrongswan/plugins/random/random_plugin.c +++ b/src/libstrongswan/plugins/random/random_plugin.c @@ -15,9 +15,24 @@ #include "random_plugin.h" +#include +#include +#include +#include +#include + #include +#include #include "random_rng.h" +#ifndef DEV_RANDOM +# define DEV_RANDOM "/dev/random" +#endif + +#ifndef DEV_URANDOM +# define DEV_URANDOM "/dev/urandom" +#endif + typedef struct private_random_plugin_t private_random_plugin_t; /** @@ -31,6 +46,41 @@ struct private_random_plugin_t { random_plugin_t public; }; +/** /dev/random file descriptor */ +static int dev_random = -1; +/** /dev/urandom file descriptor */ +static int dev_urandom = -1; + +/** + * See header. + */ +int random_plugin_get_dev_random() +{ + return dev_random; +} + +/** + * See header. + */ +int random_plugin_get_dev_urandom() +{ + return dev_urandom; +} + +/** + * Open a random device file + */ +static bool open_dev(char *file, int *fd) +{ + *fd = open(file, O_RDONLY); + if (*fd == -1) + { + DBG1(DBG_LIB, "opening \"%s\" failed: %s", file, strerror(errno)); + return FALSE; + } + return TRUE; +} + METHOD(plugin_t, get_name, char*, private_random_plugin_t *this) { @@ -52,6 +102,14 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_random_plugin_t *this) { + if (dev_random != -1) + { + close(dev_random); + } + if (dev_urandom != -1) + { + close(dev_urandom); + } free(this); } @@ -61,6 +119,7 @@ METHOD(plugin_t, destroy, void, plugin_t *random_plugin_create() { private_random_plugin_t *this; + char *urandom_file, *random_file; INIT(this, .public = { @@ -72,6 +131,17 @@ plugin_t *random_plugin_create() }, ); + urandom_file = lib->settings->get_str(lib->settings, + "libstrongswan.plugins.random.urandom", DEV_URANDOM); + random_file = lib->settings->get_str(lib->settings, + "libstrongswan.plugins.random.random", DEV_RANDOM); + if (!open_dev(urandom_file, &dev_urandom) || + !open_dev(random_file, &dev_random)) + { + destroy(this); + return NULL; + } + return &this->public.plugin; } diff --git a/src/libstrongswan/plugins/random/random_plugin.h b/src/libstrongswan/plugins/random/random_plugin.h index 7e22c3e5f..c34fa8196 100644 --- a/src/libstrongswan/plugins/random/random_plugin.h +++ b/src/libstrongswan/plugins/random/random_plugin.h @@ -39,4 +39,14 @@ struct random_plugin_t { plugin_t plugin; }; +/** + * Get the /dev/random file descriptor + */ +int random_plugin_get_dev_random(); + +/** + * Get the /dev/urandom file descriptor + */ +int random_plugin_get_dev_urandom(); + #endif /** RANDOM_PLUGIN_H_ @}*/ diff --git a/src/libstrongswan/plugins/random/random_rng.c b/src/libstrongswan/plugins/random/random_rng.c index 1d99a63d5..52cfc080e 100644 --- a/src/libstrongswan/plugins/random/random_rng.c +++ b/src/libstrongswan/plugins/random/random_rng.c @@ -15,22 +15,12 @@ */ #include -#include -#include -#include #include #include #include #include "random_rng.h" - -#ifndef DEV_RANDOM -# define DEV_RANDOM "/dev/random" -#endif - -#ifndef DEV_URANDOM -# define DEV_URANDOM "/dev/urandom" -#endif +#include "random_plugin.h" typedef struct private_random_rng_t private_random_rng_t; @@ -47,15 +37,10 @@ struct private_random_rng_t { /** * random device, depends on quality */ - int dev; - - /** - * file we read random bytes from - */ - char *file; + int fd; }; -METHOD(rng_t, get_bytes, void, +METHOD(rng_t, get_bytes, bool, private_random_rng_t *this, size_t bytes, u_int8_t *buffer) { size_t done; @@ -65,30 +50,29 @@ METHOD(rng_t, get_bytes, void, while (done < bytes) { - got = read(this->dev, buffer + done, bytes - done); + got = read(this->fd, buffer + done, bytes - done); if (got <= 0) { - DBG1(DBG_LIB, "reading from \"%s\" failed: %s, retrying...", - this->file, strerror(errno)); - close(this->dev); + DBG1(DBG_LIB, "reading from random FD %d failed: %s, retrying...", + this->fd, strerror(errno)); sleep(1); - this->dev = open(this->file, 0); } done += got; } + return TRUE; } -METHOD(rng_t, allocate_bytes, void, +METHOD(rng_t, allocate_bytes, bool, private_random_rng_t *this, size_t bytes, chunk_t *chunk) { *chunk = chunk_alloc(bytes); get_bytes(this, chunk->len, chunk->ptr); + return TRUE; } METHOD(rng_t, destroy, void, private_random_rng_t *this) { - close(this->dev); free(this); } @@ -109,22 +93,18 @@ random_rng_t *random_rng_create(rng_quality_t quality) }, ); - if (quality == RNG_TRUE) + switch (quality) { - this->file = DEV_RANDOM; - } - else - { - this->file = DEV_URANDOM; + case RNG_TRUE: + this->fd = random_plugin_get_dev_random(); + break; + case RNG_STRONG: + case RNG_WEAK: + default: + this->fd = random_plugin_get_dev_urandom(); + break; } - this->dev = open(this->file, 0); - if (this->dev < 0) - { - DBG1(DBG_LIB, "opening \"%s\" failed: %s", this->file, strerror(errno)); - free(this); - return NULL; - } return &this->public; } diff --git a/src/libstrongswan/plugins/revocation/Makefile.in b/src/libstrongswan/plugins/revocation/Makefile.in index a78762c82..e2cbbbbe0 100644 --- a/src/libstrongswan/plugins/revocation/Makefile.in +++ b/src/libstrongswan/plugins/revocation/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -86,7 +87,7 @@ libstrongswan_revocation_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_revocation_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_revocation_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -112,6 +113,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -206,11 +208,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -227,11 +232,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -247,6 +253,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -256,7 +263,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/revocation/revocation_validator.c b/src/libstrongswan/plugins/revocation/revocation_validator.c index 34f347d1a..dc8e454e7 100644 --- a/src/libstrongswan/plugins/revocation/revocation_validator.c +++ b/src/libstrongswan/plugins/revocation/revocation_validator.c @@ -103,7 +103,7 @@ static bool verify_ocsp(ocsp_response_t *response, auth_cfg_t *auth) bool verified = FALSE; wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response); - lib->credmgr->add_local_set(lib->credmgr, &wrapper->set); + lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE); subject = &response->certificate; responder = subject->get_issuer(subject); @@ -111,7 +111,7 @@ static bool verify_ocsp(ocsp_response_t *response, auth_cfg_t *auth) KEY_ANY, responder, FALSE); while (enumerator->enumerate(enumerator, &issuer, ¤t)) { - if (lib->credmgr->issued_by(lib->credmgr, subject, issuer)) + if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL)) { DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"", issuer->get_subject(issuer)); @@ -341,7 +341,7 @@ static bool verify_crl(certificate_t *crl, auth_cfg_t *auth) KEY_ANY, crl->get_issuer(crl), FALSE); while (enumerator->enumerate(enumerator, &issuer, ¤t)) { - if (lib->credmgr->issued_by(lib->credmgr, crl, issuer)) + if (lib->credmgr->issued_by(lib->credmgr, crl, issuer, NULL)) { DBG1(DBG_CFG, " crl correctly signed by \"%Y\"", issuer->get_subject(issuer)); diff --git a/src/libstrongswan/plugins/sha1/Makefile.in b/src/libstrongswan/plugins/sha1/Makefile.in index f59c7516d..5188c3fbf 100644 --- a/src/libstrongswan/plugins/sha1/Makefile.in +++ b/src/libstrongswan/plugins/sha1/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_sha1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_sha1_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_sha1_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_sha1_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/sha1/sha1_hasher.c b/src/libstrongswan/plugins/sha1/sha1_hasher.c index 4d69ad5a4..b0efbae7d 100644 --- a/src/libstrongswan/plugins/sha1/sha1_hasher.c +++ b/src/libstrongswan/plugins/sha1/sha1_hasher.c @@ -175,7 +175,7 @@ static void SHA1Final(private_sha1_hasher_t *this, u_int8_t *digest) } } -METHOD(hasher_t, reset, void, +METHOD(hasher_t, reset, bool, private_sha1_hasher_t *this) { this->state[0] = 0x67452301; @@ -185,9 +185,11 @@ METHOD(hasher_t, reset, void, this->state[4] = 0xC3D2E1F0; this->count[0] = 0; this->count[1] = 0; + + return TRUE; } -METHOD(hasher_t, get_hash, void, +METHOD(hasher_t, get_hash, bool, private_sha1_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { SHA1Update(this, chunk.ptr, chunk.len); @@ -196,9 +198,10 @@ METHOD(hasher_t, get_hash, void, SHA1Final(this, buffer); reset(this); } + return TRUE; } -METHOD(hasher_t, allocate_hash, void, +METHOD(hasher_t, allocate_hash, bool, private_sha1_hasher_t *this, chunk_t chunk, chunk_t *hash) { SHA1Update(this, chunk.ptr, chunk.len); @@ -210,6 +213,7 @@ METHOD(hasher_t, allocate_hash, void, SHA1Final(this, hash->ptr); reset(this); } + return TRUE; } METHOD(hasher_t, get_hash_size, size_t, diff --git a/src/libstrongswan/plugins/sha1/sha1_prf.c b/src/libstrongswan/plugins/sha1/sha1_prf.c index 11f588c9d..cdc494b34 100644 --- a/src/libstrongswan/plugins/sha1/sha1_prf.c +++ b/src/libstrongswan/plugins/sha1/sha1_prf.c @@ -59,7 +59,7 @@ struct private_sha1_prf_t { */ extern void SHA1Update(private_sha1_hasher_t* this, u_int8_t *data, u_int32_t len); -METHOD(prf_t, get_bytes, void, +METHOD(prf_t, get_bytes, bool, private_sha1_prf_t *this, chunk_t seed, u_int8_t *bytes) { u_int32_t *hash = (u_int32_t*)bytes; @@ -71,6 +71,8 @@ METHOD(prf_t, get_bytes, void, hash[2] = htonl(this->hasher->state[2]); hash[3] = htonl(this->hasher->state[3]); hash[4] = htonl(this->hasher->state[4]); + + return TRUE; } METHOD(prf_t, get_block_size, size_t, @@ -79,11 +81,11 @@ METHOD(prf_t, get_block_size, size_t, return HASH_SIZE_SHA1; } -METHOD(prf_t, allocate_bytes, void, +METHOD(prf_t, allocate_bytes, bool, private_sha1_prf_t *this, chunk_t seed, chunk_t *chunk) { *chunk = chunk_alloc(HASH_SIZE_SHA1); - get_bytes(this, seed, chunk->ptr); + return get_bytes(this, seed, chunk->ptr); } METHOD(prf_t, get_key_size, size_t, @@ -92,18 +94,23 @@ METHOD(prf_t, get_key_size, size_t, return sizeof(this->hasher->state); } -METHOD(prf_t, set_key, void, +METHOD(prf_t, set_key, bool, private_sha1_prf_t *this, chunk_t key) { int i, rounds; u_int32_t *iv = (u_int32_t*)key.ptr; - this->hasher->public.hasher_interface.reset(&this->hasher->public.hasher_interface); + if (!this->hasher->public.hasher_interface.reset( + &this->hasher->public.hasher_interface)) + { + return FALSE; + } rounds = min(key.len/sizeof(u_int32_t), sizeof(this->hasher->state)); for (i = 0; i < rounds; i++) { this->hasher->state[i] ^= htonl(iv[i]); } + return TRUE; } METHOD(prf_t, destroy, void, diff --git a/src/libstrongswan/plugins/sha2/Makefile.in b/src/libstrongswan/plugins/sha2/Makefile.in index c99f30e43..adf7d10b4 100644 --- a/src/libstrongswan/plugins/sha2/Makefile.in +++ b/src/libstrongswan/plugins/sha2/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -82,7 +83,7 @@ libstrongswan_sha2_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_sha2_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_sha2_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_sha2_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -108,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -202,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -223,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -243,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -252,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/sha2/sha2_hasher.c b/src/libstrongswan/plugins/sha2/sha2_hasher.c index 60fe4bd20..1c6dd2533 100644 --- a/src/libstrongswan/plugins/sha2/sha2_hasher.c +++ b/src/libstrongswan/plugins/sha2/sha2_hasher.c @@ -426,41 +426,49 @@ static void sha512_final(private_sha512_hasher_t *ctx) } while(++j < 8); } -METHOD(hasher_t, reset224, void, +METHOD(hasher_t, reset224, bool, private_sha256_hasher_t *this) { memcpy(&this->sha_H[0], &sha224_hashInit[0], sizeof(this->sha_H)); this->sha_blocks = 0; this->sha_bufCnt = 0; + + return TRUE; } -METHOD(hasher_t, reset256, void, +METHOD(hasher_t, reset256, bool, private_sha256_hasher_t *this) { memcpy(&this->sha_H[0], &sha256_hashInit[0], sizeof(this->sha_H)); this->sha_blocks = 0; this->sha_bufCnt = 0; + + return TRUE; } -METHOD(hasher_t, reset384, void, +METHOD(hasher_t, reset384, bool, private_sha512_hasher_t *this) { memcpy(&this->sha_H[0], &sha384_hashInit[0], sizeof(this->sha_H)); this->sha_blocks = 0; this->sha_blocksMSB = 0; this->sha_bufCnt = 0; + + return TRUE; } -METHOD(hasher_t, reset512, void, +METHOD(hasher_t, reset512, bool, private_sha512_hasher_t *this) { memcpy(&this->sha_H[0], &sha512_hashInit[0], sizeof(this->sha_H)); this->sha_blocks = 0; this->sha_blocksMSB = 0; this->sha_bufCnt = 0; + + return TRUE; } -METHOD(hasher_t, get_hash224, void, +METHOD(hasher_t, get_hash224, bool, private_sha256_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { sha256_write(this, chunk.ptr, chunk.len); @@ -470,9 +478,10 @@ METHOD(hasher_t, get_hash224, void, memcpy(buffer, this->sha_out, HASH_SIZE_SHA224); reset224(this); } + return TRUE; } -METHOD(hasher_t, get_hash256, void, +METHOD(hasher_t, get_hash256, bool, private_sha256_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { sha256_write(this, chunk.ptr, chunk.len); @@ -482,9 +491,10 @@ METHOD(hasher_t, get_hash256, void, memcpy(buffer, this->sha_out, HASH_SIZE_SHA256); reset256(this); } + return TRUE; } -METHOD(hasher_t, get_hash384, void, +METHOD(hasher_t, get_hash384, bool, private_sha512_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { sha512_write(this, chunk.ptr, chunk.len); @@ -494,9 +504,10 @@ METHOD(hasher_t, get_hash384, void, memcpy(buffer, this->sha_out, HASH_SIZE_SHA384); reset384(this); } + return TRUE; } -METHOD(hasher_t, get_hash512, void, +METHOD(hasher_t, get_hash512, bool, private_sha512_hasher_t *this, chunk_t chunk, u_int8_t *buffer) { sha512_write(this, chunk.ptr, chunk.len); @@ -506,9 +517,10 @@ METHOD(hasher_t, get_hash512, void, memcpy(buffer, this->sha_out, HASH_SIZE_SHA512); reset512(this); } + return TRUE; } -METHOD(hasher_t, allocate_hash224, void, +METHOD(hasher_t, allocate_hash224, bool, private_sha256_hasher_t *this, chunk_t chunk, chunk_t *hash) { chunk_t allocated_hash; @@ -522,9 +534,10 @@ METHOD(hasher_t, allocate_hash224, void, reset224(this); *hash = allocated_hash; } + return TRUE; } -METHOD(hasher_t, allocate_hash256, void, +METHOD(hasher_t, allocate_hash256, bool, private_sha256_hasher_t *this, chunk_t chunk, chunk_t *hash) { chunk_t allocated_hash; @@ -538,9 +551,10 @@ METHOD(hasher_t, allocate_hash256, void, reset256(this); *hash = allocated_hash; } + return TRUE; } -METHOD(hasher_t, allocate_hash384, void, +METHOD(hasher_t, allocate_hash384, bool, private_sha512_hasher_t *this, chunk_t chunk, chunk_t *hash) { chunk_t allocated_hash; @@ -554,9 +568,10 @@ METHOD(hasher_t, allocate_hash384, void, reset384(this); *hash = allocated_hash; } + return TRUE; } -METHOD(hasher_t, allocate_hash512, void, +METHOD(hasher_t, allocate_hash512, bool, private_sha512_hasher_t *this, chunk_t chunk, chunk_t *hash) { chunk_t allocated_hash; @@ -570,6 +585,7 @@ METHOD(hasher_t, allocate_hash512, void, reset512(this); *hash = allocated_hash; } + return TRUE; } METHOD(hasher_t, get_hash_size224, size_t, diff --git a/src/libstrongswan/plugins/soup/Makefile.in b/src/libstrongswan/plugins/soup/Makefile.in index ce4b07769..5ab3f94aa 100644 --- a/src/libstrongswan/plugins/soup/Makefile.in +++ b/src/libstrongswan/plugins/soup/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -83,7 +84,7 @@ libstrongswan_soup_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_soup_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_soup_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_soup_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/sqlite/Makefile.in b/src/libstrongswan/plugins/sqlite/Makefile.in index 391827724..f13540edb 100644 --- a/src/libstrongswan/plugins/sqlite/Makefile.in +++ b/src/libstrongswan/plugins/sqlite/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -85,7 +86,7 @@ libstrongswan_sqlite_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ @MONOLITHIC_FALSE@am_libstrongswan_sqlite_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_sqlite_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -111,6 +112,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -205,11 +207,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -226,11 +231,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -246,6 +252,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -255,7 +262,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/sqlite/sqlite_database.c b/src/libstrongswan/plugins/sqlite/sqlite_database.c index f9e06199e..0fb3c7fff 100644 --- a/src/libstrongswan/plugins/sqlite/sqlite_database.c +++ b/src/libstrongswan/plugins/sqlite/sqlite_database.c @@ -206,6 +206,7 @@ static bool sqlite_enumerator_enumerate(sqlite_enumerator_t *this, ...) } default: DBG1(DBG_LIB, "invalid result type supplied"); + va_end(args); return FALSE; } } diff --git a/src/libstrongswan/plugins/test_vectors/Makefile.in b/src/libstrongswan/plugins/test_vectors/Makefile.in index 7e0271b13..f717ad6d9 100644 --- a/src/libstrongswan/plugins/test_vectors/Makefile.in +++ b/src/libstrongswan/plugins/test_vectors/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -91,7 +92,7 @@ libstrongswan_test_vectors_la_LINK = $(LIBTOOL) --tag=CC \ @MONOLITHIC_FALSE@am_libstrongswan_test_vectors_la_rpath = -rpath \ @MONOLITHIC_FALSE@ $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_test_vectors_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -117,6 +118,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -211,11 +213,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -232,11 +237,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -252,6 +258,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -261,7 +268,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors.h b/src/libstrongswan/plugins/test_vectors/test_vectors.h index 40fb51da6..a00469779 100644 --- a/src/libstrongswan/plugins/test_vectors/test_vectors.h +++ b/src/libstrongswan/plugins/test_vectors/test_vectors.h @@ -140,6 +140,7 @@ TEST_VECTOR_HASHER(md5_7) TEST_VECTOR_HASHER(sha1_1) TEST_VECTOR_HASHER(sha1_2) TEST_VECTOR_HASHER(sha1_3) +TEST_VECTOR_HASHER(sha1_4) TEST_VECTOR_HASHER(sha224_1) TEST_VECTOR_HASHER(sha224_2) TEST_VECTOR_HASHER(sha224_3) diff --git a/src/libstrongswan/plugins/test_vectors/test_vectors/sha1.c b/src/libstrongswan/plugins/test_vectors/test_vectors/sha1.c index 51f22716e..669adf8c6 100644 --- a/src/libstrongswan/plugins/test_vectors/test_vectors/sha1.c +++ b/src/libstrongswan/plugins/test_vectors/test_vectors/sha1.c @@ -49,3 +49,9 @@ hasher_test_vector_t sha1_3 = { "\x2b\xad\x27\xb3" }; +hasher_test_vector_t sha1_4 = { + .alg = HASH_SHA1, .len = 62, + .data = "12345678901234567890123456789012345678901234567890123456789012", + .hash = "\xd8\xd0\x73\xb3\x83\x15\x66\x17\xc5\xca\xdf\x17\xf6\x15\x96\xa3" + "\x84\x0a\xfd\x8b" +}; diff --git a/src/libstrongswan/plugins/x509/Makefile.in b/src/libstrongswan/plugins/x509/Makefile.in index 8c05cb22d..6d9f88647 100644 --- a/src/libstrongswan/plugins/x509/Makefile.in +++ b/src/libstrongswan/plugins/x509/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -84,7 +85,7 @@ libstrongswan_x509_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(libstrongswan_x509_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_x509_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_x509_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -110,6 +111,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -204,11 +206,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -225,11 +230,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -245,6 +251,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -254,7 +261,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libstrongswan/plugins/x509/x509_ac.c b/src/libstrongswan/plugins/x509/x509_ac.c index a2cb589e0..d6ca8c4fa 100644 --- a/src/libstrongswan/plugins/x509/x509_ac.c +++ b/src/libstrongswan/plugins/x509/x509_ac.c @@ -701,7 +701,7 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_ac_t *this, certificate_t *issuer) + private_x509_ac_t *this, certificate_t *issuer, signature_scheme_t *schemep) { public_key_t *key; signature_scheme_t scheme; @@ -750,6 +750,10 @@ METHOD(certificate_t, issued_by, bool, } valid = key->verify(key, scheme, this->certificateInfo, this->signature); key->destroy(key); + if (valid && schemep) + { + *schemep = scheme; + } return valid; } diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 4859f4310..2269eb453 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -752,6 +752,9 @@ static void parse_extendedKeyUsage(chunk_t blob, int level0, case OID_CLIENT_AUTH: this->flags |= X509_CLIENT_AUTH; break; + case OID_IKE_INTERMEDIATE: + this->flags |= X509_IKE_INTERMEDIATE; + break; case OID_OCSP_SIGNING: this->flags |= X509_OCSP_SIGNER; break; @@ -1105,19 +1108,19 @@ static void parse_policyConstraints(chunk_t blob, int level0, * ASN.1 definition of ipAddrBlocks according to RFC 3779 */ static const asn1Object_t ipAddrBlocksObjects[] = { - { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ - { 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ - { 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ - { 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ - { 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ - { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ + { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ + { 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ + { 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ + { 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ + { 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; @@ -1480,18 +1483,20 @@ end: /* check if the certificate is self-signed */ if (this->public.interface.interface.issued_by( &this->public.interface.interface, - &this->public.interface.interface)) + &this->public.interface.interface, + NULL)) { this->flags |= X509_SELF_SIGNED; } /* create certificate hash */ hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) + if (!hasher || + !hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash)) { + DESTROY_IF(hasher); DBG1(DBG_ASN, " unable to create hash of certificate, SHA1 not supported"); return FALSE; } - hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash); hasher->destroy(hasher); } return success; @@ -1565,7 +1570,8 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_cert_t *this, certificate_t *issuer) + private_x509_cert_t *this, certificate_t *issuer, + signature_scheme_t *schemep) { public_key_t *key; signature_scheme_t scheme; @@ -1609,6 +1615,10 @@ METHOD(certificate_t, issued_by, bool, } valid = key->verify(key, scheme, this->tbsCertificate, this->signature); key->destroy(key); + if (valid && schemep) + { + *schemep = scheme; + } return valid; } @@ -1994,6 +2004,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty; chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty; chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty; + chunk_t ikeIntermediate = chunk_empty; identification_t *issuer, *subject; chunk_t key_info; signature_scheme_t scheme; @@ -2107,7 +2118,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, asn1_wrap(ASN1_BIT_STRING, "c", keyUsageBits))); } - /* add serverAuth extendedKeyUsage flag */ + /* add extendedKeyUsage flags */ if (cert->flags & X509_SERVER_AUTH) { serverAuth = asn1_build_known_oid(OID_SERVER_AUTH); @@ -2116,20 +2127,24 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, { clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH); } - - /* add ocspSigning extendedKeyUsage flag */ + if (cert->flags & X509_IKE_INTERMEDIATE) + { + ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE); + } if (cert->flags & X509_OCSP_SIGNER) { ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING); } - if (serverAuth.ptr || clientAuth.ptr || ocspSigning.ptr) + if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr || + ocspSigning.ptr) { extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_EXTENDED_KEY_USAGE), asn1_wrap(ASN1_OCTET_STRING, "m", - asn1_wrap(ASN1_SEQUENCE, "mmm", - serverAuth, clientAuth, ocspSigning))); + asn1_wrap(ASN1_SEQUENCE, "mmmm", + serverAuth, clientAuth, ikeIntermediate, + ocspSigning))); } /* add subjectKeyIdentifier to CA and OCSP signer certificates */ @@ -2330,11 +2345,12 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, asn1_bitstring("c", cert->signature)); hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) + if (!hasher || + !hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash)) { + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, cert->encoding, &cert->encoding_hash); hasher->destroy(hasher); return TRUE; } diff --git a/src/libstrongswan/plugins/x509/x509_crl.c b/src/libstrongswan/plugins/x509/x509_crl.c index 7bcca16a3..47621103e 100644 --- a/src/libstrongswan/plugins/x509/x509_crl.c +++ b/src/libstrongswan/plugins/x509/x509_crl.c @@ -221,7 +221,7 @@ static bool parse(private_x509_crl_t *this) { asn1_parser_t *parser; chunk_t object; - chunk_t extnID; + chunk_t extnID = chunk_empty; chunk_t userCertificate = chunk_empty; int objectID; int sig_alg = OID_UNKNOWN; @@ -442,7 +442,7 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_crl_t *this, certificate_t *issuer) + private_x509_crl_t *this, certificate_t *issuer, signature_scheme_t *schemep) { public_key_t *key; signature_scheme_t scheme; @@ -490,6 +490,10 @@ METHOD(certificate_t, issued_by, bool, } valid = key->verify(key, scheme, this->tbsCertList, this->signature); key->destroy(key); + if (valid && schemep) + { + *schemep = scheme; + } return valid; } diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_request.c b/src/libstrongswan/plugins/x509/x509_ocsp_request.c index 33d0aa792..bbd1c5905 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_request.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_request.c @@ -159,22 +159,24 @@ static chunk_t build_requestList(private_x509_ocsp_request_t *this) enumerator_t *enumerator; issuer = cert->get_subject(cert); - hasher->allocate_hash(hasher, issuer->get_encoding(issuer), - &issuerNameHash); - hasher->destroy(hasher); - - enumerator = this->candidates->create_enumerator(this->candidates); - while (enumerator->enumerate(enumerator, &x509)) + if (hasher->allocate_hash(hasher, issuer->get_encoding(issuer), + &issuerNameHash)) { - chunk_t request, serialNumber; - - serialNumber = x509->get_serial(x509); - request = build_Request(this, issuerNameHash, issuerKeyHash, - serialNumber); - list = chunk_cat("mm", list, request); + enumerator = this->candidates->create_enumerator( + this->candidates); + while (enumerator->enumerate(enumerator, &x509)) + { + chunk_t request, serialNumber; + + serialNumber = x509->get_serial(x509); + request = build_Request(this, issuerNameHash, + issuerKeyHash, serialNumber); + list = chunk_cat("mm", list, request); + } + enumerator->destroy(enumerator); + chunk_free(&issuerNameHash); } - enumerator->destroy(enumerator); - chunk_free(&issuerNameHash); + hasher->destroy(hasher); } } else @@ -199,15 +201,15 @@ static chunk_t build_nonce(private_x509_ocsp_request_t *this) rng_t *rng; rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (rng) + if (!rng || !rng->allocate_bytes(rng, NONCE_LEN, &this->nonce)) { - rng->allocate_bytes(rng, NONCE_LEN, &this->nonce); - rng->destroy(rng); - return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_nonce_oid, - asn1_simple_object(ASN1_OCTET_STRING, this->nonce)); + DBG1(DBG_LIB, "creating OCSP request nonce failed, no RNG found"); + DESTROY_IF(rng); + return chunk_empty; } - DBG1(DBG_LIB, "creating OCSP request nonce failed, no RNG found"); - return chunk_empty; + rng->destroy(rng); + return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_nonce_oid, + asn1_simple_object(ASN1_OCTET_STRING, this->nonce)); } /** @@ -364,7 +366,8 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_ocsp_request_t *this, certificate_t *issuer) + private_x509_ocsp_request_t *this, certificate_t *issuer, + signature_scheme_t *scheme) { DBG1(DBG_LIB, "OCSP request validation not implemented!"); return FALSE; diff --git a/src/libstrongswan/plugins/x509/x509_ocsp_response.c b/src/libstrongswan/plugins/x509/x509_ocsp_response.c index 7dfef3993..27497e0e3 100644 --- a/src/libstrongswan/plugins/x509/x509_ocsp_response.c +++ b/src/libstrongswan/plugins/x509/x509_ocsp_response.c @@ -201,19 +201,22 @@ METHOD(ocsp_response_t, get_status, cert_validation_t, /* check issuerNameHash, if available */ else if (response->issuerNameHash.ptr) { + id = issuercert->get_subject(issuercert); hasher = lib->crypto->create_hasher(lib->crypto, hasher_algorithm_from_oid(response->hashAlgorithm)); - if (!hasher) + if (!hasher || + !hasher->allocate_hash(hasher, id->get_encoding(id), &hash)) { + DESTROY_IF(hasher); continue; } - id = issuercert->get_subject(issuercert); - hasher->allocate_hash(hasher, id->get_encoding(id), &hash); hasher->destroy(hasher); if (!chunk_equals(hash, response->issuerNameHash)) { + free(hash.ptr); continue; } + free(hash.ptr); } else { @@ -670,7 +673,8 @@ METHOD(certificate_t, has_issuer, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_ocsp_response_t *this, certificate_t *issuer) + private_x509_ocsp_response_t *this, certificate_t *issuer, + signature_scheme_t *schemep) { public_key_t *key; signature_scheme_t scheme; @@ -722,6 +726,10 @@ METHOD(certificate_t, issued_by, bool, } valid = key->verify(key, scheme, this->tbsResponseData, this->signature); key->destroy(key); + if (valid && schemep) + { + *schemep = scheme; + } return valid; } diff --git a/src/libstrongswan/plugins/x509/x509_pkcs10.c b/src/libstrongswan/plugins/x509/x509_pkcs10.c index ca08db2c6..9fa91fed2 100644 --- a/src/libstrongswan/plugins/x509/x509_pkcs10.c +++ b/src/libstrongswan/plugins/x509/x509_pkcs10.c @@ -123,10 +123,12 @@ METHOD(certificate_t, has_subject, id_match_t, } METHOD(certificate_t, issued_by, bool, - private_x509_pkcs10_t *this, certificate_t *issuer) + private_x509_pkcs10_t *this, certificate_t *issuer, + signature_scheme_t *schemep) { public_key_t *key; signature_scheme_t scheme; + bool valid; if (&this->public.interface.interface != issuer) { @@ -150,8 +152,13 @@ METHOD(certificate_t, issued_by, bool, { return FALSE; } - return key->verify(key, scheme, this->certificationRequestInfo, - this->signature); + valid = key->verify(key, scheme, this->certificationRequestInfo, + this->signature); + if (valid && schemep) + { + *schemep = scheme; + } + return valid; } METHOD(certificate_t, get_public_key, public_key_t*, @@ -327,7 +334,7 @@ static bool parse_challengePassword(private_x509_pkcs10_t *this, chunk_t blob, i return FALSE; } DBG2(DBG_ASN, "L%d - challengePassword:", level); - DBG4(DBG_ASN, " '%.*s'", blob.len, blob.ptr); + DBG4(DBG_ASN, " '%.*s'", (int)blob.len, blob.ptr); return TRUE; } @@ -441,7 +448,7 @@ end: if (success) { /* check if the certificate request is self-signed */ - if (issued_by(this, &this->public.interface.interface)) + if (issued_by(this, &this->public.interface.interface, NULL)) { this->self_signed = TRUE; } diff --git a/src/libstrongswan/plugins/x509/x509_plugin.c b/src/libstrongswan/plugins/x509/x509_plugin.c index ed6fbfd91..15fea7ee0 100644 --- a/src/libstrongswan/plugins/x509/x509_plugin.c +++ b/src/libstrongswan/plugins/x509/x509_plugin.c @@ -52,6 +52,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_REGISTER(CERT_DECODE, x509_cert_load, TRUE), PLUGIN_PROVIDE(CERT_DECODE, CERT_X509), PLUGIN_DEPENDS(HASHER, HASH_SHA1), + PLUGIN_SDEPEND(PUBKEY, KEY_RSA), + PLUGIN_SDEPEND(PUBKEY, KEY_ECDSA), + PLUGIN_SDEPEND(PUBKEY, KEY_DSA), PLUGIN_REGISTER(CERT_ENCODE, x509_ac_gen, FALSE), PLUGIN_PROVIDE(CERT_ENCODE, CERT_X509_AC), diff --git a/src/libstrongswan/plugins/xcbc/Makefile.am b/src/libstrongswan/plugins/xcbc/Makefile.am index 7de306832..28e99f650 100644 --- a/src/libstrongswan/plugins/xcbc/Makefile.am +++ b/src/libstrongswan/plugins/xcbc/Makefile.am @@ -10,7 +10,6 @@ plugin_LTLIBRARIES = libstrongswan-xcbc.la endif libstrongswan_xcbc_la_SOURCES = \ - xcbc_plugin.h xcbc_plugin.c xcbc.h xcbc.c \ - xcbc_prf.h xcbc_prf.c xcbc_signer.h xcbc_signer.c + xcbc_plugin.h xcbc_plugin.c xcbc.h xcbc.c libstrongswan_xcbc_la_LDFLAGS = -module -avoid-version diff --git a/src/libstrongswan/plugins/xcbc/Makefile.in b/src/libstrongswan/plugins/xcbc/Makefile.in index ae23ce730..b4d0a2160 100644 --- a/src/libstrongswan/plugins/xcbc/Makefile.in +++ b/src/libstrongswan/plugins/xcbc/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -75,15 +76,14 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(plugindir)" LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) libstrongswan_xcbc_la_LIBADD = -am_libstrongswan_xcbc_la_OBJECTS = xcbc_plugin.lo xcbc.lo xcbc_prf.lo \ - xcbc_signer.lo +am_libstrongswan_xcbc_la_OBJECTS = xcbc_plugin.lo xcbc.lo libstrongswan_xcbc_la_OBJECTS = $(am_libstrongswan_xcbc_la_OBJECTS) libstrongswan_xcbc_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libstrongswan_xcbc_la_LDFLAGS) $(LDFLAGS) -o $@ @MONOLITHIC_FALSE@am_libstrongswan_xcbc_la_rpath = -rpath $(plugindir) @MONOLITHIC_TRUE@am_libstrongswan_xcbc_la_rpath = -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +109,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +204,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +228,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +249,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +259,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -286,8 +291,7 @@ AM_CFLAGS = -rdynamic @MONOLITHIC_TRUE@noinst_LTLIBRARIES = libstrongswan-xcbc.la @MONOLITHIC_FALSE@plugin_LTLIBRARIES = libstrongswan-xcbc.la libstrongswan_xcbc_la_SOURCES = \ - xcbc_plugin.h xcbc_plugin.c xcbc.h xcbc.c \ - xcbc_prf.h xcbc_prf.c xcbc_signer.h xcbc_signer.c + xcbc_plugin.h xcbc_plugin.c xcbc.h xcbc.c libstrongswan_xcbc_la_LDFLAGS = -module -avoid-version all: all-am @@ -375,8 +379,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcbc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcbc_plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcbc_prf.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xcbc_signer.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/libstrongswan/plugins/xcbc/xcbc.c b/src/libstrongswan/plugins/xcbc/xcbc.c index 53629abe5..1bb7e640a 100644 --- a/src/libstrongswan/plugins/xcbc/xcbc.c +++ b/src/libstrongswan/plugins/xcbc/xcbc.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -18,20 +19,23 @@ #include "xcbc.h" #include +#include +#include +#include -typedef struct private_xcbc_t private_xcbc_t; +typedef struct private_mac_t private_mac_t; /** - * Private data of a xcbc_t object. + * Private data of a mac_t object. * * The variable names are the same as in the RFC. */ -struct private_xcbc_t { +struct private_mac_t { /** - * Public xcbc_t interface. + * Public mac_t interface. */ - xcbc_t public; + mac_t public; /** * Block size, in bytes @@ -77,7 +81,7 @@ struct private_xcbc_t { /** * xcbc supplied data, but do not run final operation */ -static void update(private_xcbc_t *this, chunk_t data) +static bool update(private_mac_t *this, chunk_t data) { chunk_t iv; @@ -90,7 +94,7 @@ static void update(private_xcbc_t *this, chunk_t data) { /* no complete block, just copy into remaining */ memcpy(this->remaining + this->remaining_bytes, data.ptr, data.len); this->remaining_bytes += data.len; - return; + return TRUE; } iv = chunk_alloca(this->b); @@ -106,7 +110,10 @@ static void update(private_xcbc_t *this, chunk_t data) this->b - this->remaining_bytes); data = chunk_skip(data, this->b - this->remaining_bytes); memxor(this->e, this->remaining, this->b); - this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); + if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL)) + { + return FALSE; + } /* process blocks M[2] ... M[n-1] */ while (data.len > this->b) @@ -114,18 +121,24 @@ static void update(private_xcbc_t *this, chunk_t data) memcpy(this->remaining, data.ptr, this->b); data = chunk_skip(data, this->b); memxor(this->e, this->remaining, this->b); - this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); + if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), + iv, NULL)) + { + return FALSE; + } } /* store remaining bytes of block M[n] */ memcpy(this->remaining, data.ptr, data.len); this->remaining_bytes = data.len; + + return TRUE; } /** * run last round, data is in this->e */ -static void final(private_xcbc_t *this, u_int8_t *out) +static bool final(private_mac_t *this, u_int8_t *out) { chunk_t iv; @@ -141,7 +154,6 @@ static void final(private_xcbc_t *this, u_int8_t *out) */ memxor(this->e, this->remaining, this->b); memxor(this->e, this->k2, this->b); - this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); } else { @@ -164,7 +176,10 @@ static void final(private_xcbc_t *this, u_int8_t *out) */ memxor(this->e, this->remaining, this->b); memxor(this->e, this->k3, this->b); - this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL); + } + if (!this->k1->encrypt(this->k1, chunk_create(this->e, this->b), iv, NULL)) + { + return FALSE; } memcpy(out, this->e, this->b); @@ -173,28 +188,34 @@ static void final(private_xcbc_t *this, u_int8_t *out) memset(this->e, 0, this->b); this->remaining_bytes = 0; this->zero = TRUE; + + return TRUE; } -METHOD(xcbc_t, get_mac, void, - private_xcbc_t *this, chunk_t data, u_int8_t *out) +METHOD(mac_t, get_mac, bool, + private_mac_t *this, chunk_t data, u_int8_t *out) { /* update E, do not process last block */ - update(this, data); + if (!update(this, data)) + { + return FALSE; + } if (out) { /* if not in append mode, process last block and output result */ - final(this, out); + return final(this, out); } + return TRUE; } -METHOD(xcbc_t, get_block_size, size_t, - private_xcbc_t *this) +METHOD(mac_t, get_mac_size, size_t, + private_mac_t *this) { return this->b; } -METHOD(xcbc_t, set_key, void, - private_xcbc_t *this, chunk_t key) +METHOD(mac_t, set_key, bool, + private_mac_t *this, chunk_t key) { chunk_t iv, k1, lengthened; @@ -213,8 +234,11 @@ METHOD(xcbc_t, set_key, void, { /* shorten key using xcbc */ lengthened = chunk_alloca(this->b); memset(lengthened.ptr, 0, lengthened.len); - set_key(this, lengthened); - get_mac(this, key, lengthened.ptr); + if (!set_key(this, lengthened) || + !get_mac(this, key, lengthened.ptr)) + { + return FALSE; + } } k1 = chunk_alloca(this->b); @@ -228,20 +252,26 @@ METHOD(xcbc_t, set_key, void, * K2 = 0x02020202020202020202020202020202 encrypted with Key K * K3 = 0x03030303030303030303030303030303 encrypted with Key K */ - this->k1->set_key(this->k1, lengthened); + + memset(k1.ptr, 0x01, this->b); memset(this->k2, 0x02, this->b); - this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL); memset(this->k3, 0x03, this->b); - this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL); - memset(k1.ptr, 0x01, this->b); - this->k1->encrypt(this->k1, k1, iv, NULL); - this->k1->set_key(this->k1, k1); + if (!this->k1->set_key(this->k1, lengthened) || + !this->k1->encrypt(this->k1, chunk_create(this->k2, this->b), iv, NULL) || + !this->k1->encrypt(this->k1, chunk_create(this->k3, this->b), iv, NULL) || + !this->k1->encrypt(this->k1, k1, iv, NULL) || + !this->k1->set_key(this->k1, k1)) + { + memwipe(k1.ptr, k1.len); + return FALSE; + } memwipe(k1.ptr, k1.len); + return TRUE; } -METHOD(xcbc_t, destroy, void, - private_xcbc_t *this) +METHOD(mac_t, destroy, void, + private_mac_t *this) { this->k1->destroy(this->k1); memwipe(this->k2, this->b); @@ -256,9 +286,9 @@ METHOD(xcbc_t, destroy, void, /* * Described in header */ -xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size) +static mac_t *xcbc_create(encryption_algorithm_t algo, size_t key_size) { - private_xcbc_t *this; + private_mac_t *this; crypter_t *crypter; u_int8_t b; @@ -278,7 +308,7 @@ xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size) INIT(this, .public = { .get_mac = _get_mac, - .get_block_size = _get_block_size, + .get_mac_size = _get_mac_size, .set_key = _set_key, .destroy = _destroy, }, @@ -295,3 +325,55 @@ xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size) return &this->public; } +/* + * Described in header. + */ +prf_t *xcbc_prf_create(pseudo_random_function_t algo) +{ + mac_t *xcbc; + + switch (algo) + { + case PRF_AES128_XCBC: + xcbc = xcbc_create(ENCR_AES_CBC, 16); + break; + case PRF_CAMELLIA128_XCBC: + xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16); + break; + default: + return NULL; + } + if (xcbc) + { + return mac_prf_create(xcbc); + } + return NULL; +} + +/* + * Described in header + */ +signer_t *xcbc_signer_create(integrity_algorithm_t algo) +{ + size_t trunc; + mac_t *xcbc; + + switch (algo) + { + case AUTH_AES_XCBC_96: + xcbc = xcbc_create(ENCR_AES_CBC, 16); + trunc = 12; + break; + case AUTH_CAMELLIA_XCBC_96: + xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16); + trunc = 12; + break; + default: + return NULL; + } + if (xcbc) + { + return mac_signer_create(xcbc, trunc); + } + return NULL; +} diff --git a/src/libstrongswan/plugins/xcbc/xcbc.h b/src/libstrongswan/plugins/xcbc/xcbc.h index 5d5eb04fb..a36069a17 100644 --- a/src/libstrongswan/plugins/xcbc/xcbc.h +++ b/src/libstrongswan/plugins/xcbc/xcbc.h @@ -14,6 +14,11 @@ */ /** + * Message authentication using CBC crypter. + * + * This class implements the message authentication algorithm + * described in RFC3566. + * * @defgroup xcbc xcbc * @{ @ingroup xcbc_p */ @@ -21,58 +26,23 @@ #ifndef XCBC_H_ #define XCBC_H_ -typedef struct xcbc_t xcbc_t; - -#include +#include +#include /** - * Message authentication using CBC crypter. + * Creates a new prf_t object based on a XCBC MAC. * - * This class implements the message authentication algorithm - * described in RFC3566. + * @param algo algorithm to implement + * @return prf_t object, NULL if not supported */ -struct xcbc_t { - - /** - * Generate message authentication code. - * - * If buffer is NULL, no result is given back. A next call will - * append the data to already supplied data. If buffer is not NULL, - * the mac of all apended data is calculated, returned and the - * state of the xcbc_t is reseted. - * - * @param data chunk of data to authenticate - * @param buffer pointer where the generated bytes will be written - */ - void (*get_mac) (xcbc_t *this, chunk_t data, u_int8_t *buffer); - - /** - * Get the block size of this xcbc_t object. - * - * @return block size in bytes - */ - size_t (*get_block_size) (xcbc_t *this); - - /** - * Set the key for this xcbc_t object. - * - * @param key key to set - */ - void (*set_key) (xcbc_t *this, chunk_t key); - - /** - * Destroys a xcbc_t object. - */ - void (*destroy) (xcbc_t *this); -}; +prf_t *xcbc_prf_create(pseudo_random_function_t algo); /** - * Creates a new xcbc_t object. + * Creates a new signer_t object based on a XCBC MAC. * - * @param algo underlying crypto algorithm - * @param key_size key size to use, if required for algorithm - * @return xcbc_t object, NULL if not supported + * @param algo algorithm to implement + * @return signer_t, NULL if not supported */ -xcbc_t *xcbc_create(encryption_algorithm_t algo, size_t key_size); +signer_t *xcbc_signer_create(integrity_algorithm_t algo); #endif /** XCBC_H_ @}*/ diff --git a/src/libstrongswan/plugins/xcbc/xcbc_plugin.c b/src/libstrongswan/plugins/xcbc/xcbc_plugin.c index 3c3b9d12a..4706a9574 100644 --- a/src/libstrongswan/plugins/xcbc/xcbc_plugin.c +++ b/src/libstrongswan/plugins/xcbc/xcbc_plugin.c @@ -16,8 +16,7 @@ #include "xcbc_plugin.h" #include -#include "xcbc_signer.h" -#include "xcbc_prf.h" +#include "xcbc.h" typedef struct private_xcbc_plugin_t private_xcbc_plugin_t; diff --git a/src/libstrongswan/plugins/xcbc/xcbc_prf.c b/src/libstrongswan/plugins/xcbc/xcbc_prf.c deleted file mode 100644 index ac9e1fda0..000000000 --- a/src/libstrongswan/plugins/xcbc/xcbc_prf.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xcbc_prf.h" - -#include "xcbc.h" - -typedef struct private_xcbc_prf_t private_xcbc_prf_t; - -/** - * Private data of a xcbc_prf_t object. - */ -struct private_xcbc_prf_t { - - /** - * Public xcbc_prf_t interface. - */ - xcbc_prf_t public; - - /** - * xcbc to use for generation. - */ - xcbc_t *xcbc; -}; - -METHOD(prf_t, get_bytes, void, - private_xcbc_prf_t *this, chunk_t seed, u_int8_t *buffer) -{ - this->xcbc->get_mac(this->xcbc, seed, buffer); -} - -METHOD(prf_t, allocate_bytes, void, - private_xcbc_prf_t *this, chunk_t seed, chunk_t *chunk) -{ - if (chunk) - { - *chunk = chunk_alloc(this->xcbc->get_block_size(this->xcbc)); - get_bytes(this, seed, chunk->ptr); - } - else - { - get_bytes(this, seed, NULL); - } -} - -METHOD(prf_t, get_block_size, size_t, - private_xcbc_prf_t *this) -{ - return this->xcbc->get_block_size(this->xcbc); -} - -METHOD(prf_t, get_key_size, size_t, - private_xcbc_prf_t *this) -{ - /* in xcbc, block and key size are always equal */ - return this->xcbc->get_block_size(this->xcbc); -} - -METHOD(prf_t, set_key, void, - private_xcbc_prf_t *this, chunk_t key) -{ - this->xcbc->set_key(this->xcbc, key); -} - -METHOD(prf_t, destroy, void, - private_xcbc_prf_t *this) -{ - this->xcbc->destroy(this->xcbc); - free(this); -} - -/* - * Described in header. - */ -xcbc_prf_t *xcbc_prf_create(pseudo_random_function_t algo) -{ - private_xcbc_prf_t *this; - xcbc_t *xcbc; - - switch (algo) - { - case PRF_AES128_XCBC: - xcbc = xcbc_create(ENCR_AES_CBC, 16); - break; - case PRF_CAMELLIA128_XCBC: - xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16); - break; - default: - return NULL; - } - if (!xcbc) - { - return NULL; - } - - INIT(this, - .public = { - .prf = { - .get_bytes = _get_bytes, - .allocate_bytes = _allocate_bytes, - .get_block_size = _get_block_size, - .get_key_size = _get_key_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .xcbc = xcbc, - ); - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/xcbc/xcbc_prf.h b/src/libstrongswan/plugins/xcbc/xcbc_prf.h deleted file mode 100644 index 294a853b4..000000000 --- a/src/libstrongswan/plugins/xcbc/xcbc_prf.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xcbc_prf xcbc_prf - * @{ @ingroup xcbc_p - */ - -#ifndef PRF_XCBC_H_ -#define PRF_XCBC_H_ - -typedef struct xcbc_prf_t xcbc_prf_t; - -#include - -/** - * Implementation of prf_t on CBC block cipher using XCBC, RFC3664/RFC4434. - * - * This simply wraps a xcbc_t in a prf_t. More a question of - * interface matching. - */ -struct xcbc_prf_t { - - /** - * Implements prf_t interface. - */ - prf_t prf; -}; - -/** - * Creates a new xcbc_prf_t object. - * - * @param algo algorithm to implement - * @return xcbc_prf_t object, NULL if hash not supported - */ -xcbc_prf_t *xcbc_prf_create(pseudo_random_function_t algo); - -#endif /** PRF_XCBC_SHA1_H_ @}*/ diff --git a/src/libstrongswan/plugins/xcbc/xcbc_signer.c b/src/libstrongswan/plugins/xcbc/xcbc_signer.c deleted file mode 100644 index ece592323..000000000 --- a/src/libstrongswan/plugins/xcbc/xcbc_signer.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xcbc_signer.h" -#include "xcbc.h" - -typedef struct private_xcbc_signer_t private_xcbc_signer_t; - -/** - * Private data structure with signing context. - */ -struct private_xcbc_signer_t { - - /** - * Public interface of xcbc_signer_t. - */ - xcbc_signer_t public; - - /** - * Assigned xcbc function. - */ - xcbc_t *xcbc; - - /** - * Block size (truncation of XCBC MAC) - */ - size_t block_size; -}; - -METHOD(signer_t, get_signature, void, - private_xcbc_signer_t *this, chunk_t data, u_int8_t *buffer) -{ - if (buffer == NULL) - { /* append mode */ - this->xcbc->get_mac(this->xcbc, data, NULL); - } - else - { - u_int8_t mac[this->xcbc->get_block_size(this->xcbc)]; - - this->xcbc->get_mac(this->xcbc, data, mac); - memcpy(buffer, mac, this->block_size); - } -} - -METHOD(signer_t, allocate_signature, void, - private_xcbc_signer_t *this, chunk_t data, chunk_t *chunk) -{ - if (chunk == NULL) - { /* append mode */ - this->xcbc->get_mac(this->xcbc, data, NULL); - } - else - { - u_int8_t mac[this->xcbc->get_block_size(this->xcbc)]; - - this->xcbc->get_mac(this->xcbc, data, mac); - - chunk->ptr = malloc(this->block_size); - chunk->len = this->block_size; - - memcpy(chunk->ptr, mac, this->block_size); - } -} - -METHOD(signer_t, verify_signature, bool, - private_xcbc_signer_t *this, chunk_t data, chunk_t signature) -{ - u_int8_t mac[this->xcbc->get_block_size(this->xcbc)]; - - if (signature.len != this->block_size) - { - return FALSE; - } - - this->xcbc->get_mac(this->xcbc, data, mac); - return memeq(signature.ptr, mac, this->block_size); -} - -METHOD(signer_t, get_key_size, size_t, - private_xcbc_signer_t *this) -{ - return this->xcbc->get_block_size(this->xcbc); -} - -METHOD(signer_t, get_block_size, size_t, - private_xcbc_signer_t *this) -{ - return this->block_size; -} - -METHOD(signer_t, set_key, void, - private_xcbc_signer_t *this, chunk_t key) -{ - this->xcbc->set_key(this->xcbc, key); -} - -METHOD(signer_t, destroy, void, - private_xcbc_signer_t *this) -{ - this->xcbc->destroy(this->xcbc); - free(this); -} - -/* - * Described in header - */ -xcbc_signer_t *xcbc_signer_create(integrity_algorithm_t algo) -{ - private_xcbc_signer_t *this; - size_t trunc; - xcbc_t *xcbc; - - switch (algo) - { - case AUTH_AES_XCBC_96: - xcbc = xcbc_create(ENCR_AES_CBC, 16); - trunc = 12; - break; - case AUTH_CAMELLIA_XCBC_96: - xcbc = xcbc_create(ENCR_CAMELLIA_CBC, 16); - trunc = 12; - break; - default: - return NULL; - } - if (xcbc == NULL) - { - return NULL; - } - - INIT(this, - .public = { - .signer = { - .get_signature = _get_signature, - .allocate_signature = _allocate_signature, - .verify_signature = _verify_signature, - .get_key_size = _get_key_size, - .get_block_size = _get_block_size, - .set_key = _set_key, - .destroy = _destroy, - }, - }, - .xcbc = xcbc, - .block_size = min(trunc, xcbc->get_block_size(xcbc)), - ); - - return &this->public; -} - diff --git a/src/libstrongswan/plugins/xcbc/xcbc_signer.h b/src/libstrongswan/plugins/xcbc/xcbc_signer.h deleted file mode 100644 index 56b55f223..000000000 --- a/src/libstrongswan/plugins/xcbc/xcbc_signer.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xcbc_signer xcbc_signer - * @{ @ingroup xcbc_p - */ - -#ifndef XCBC_SIGNER_H_ -#define XCBC_SIGNER_H_ - -typedef struct xcbc_signer_t xcbc_signer_t; - -#include - -/** - * Implementation of signer_t based on CBC symmetric cypher. XCBC, RFC3566. - */ -struct xcbc_signer_t { - - /** - * Implements signer_t interface. - */ - signer_t signer; -}; - -/** - * Creates a new xcbc_signer_t. - * - * @param algo algorithm to implement - * @return xcbc_signer_t, NULL if not supported - */ -xcbc_signer_t *xcbc_signer_create(integrity_algorithm_t algo); - -#endif /** XCBC_SIGNER_H_ @}*/ diff --git a/src/libstrongswan/printf_hook.c b/src/libstrongswan/printf_hook.c index c3b5191fd..6e51aa4c3 100644 --- a/src/libstrongswan/printf_hook.c +++ b/src/libstrongswan/printf_hook.c @@ -86,21 +86,18 @@ static printf_hook_handler_t *printf_hooks[NUM_HANDLERS]; static int custom_print(FILE *stream, const struct printf_info *info, const void *const *args) { - int written; - char buf[PRINTF_BUF_LEN]; printf_hook_spec_t spec; printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(info->spec)]; + printf_hook_data_t data = { + .stream = stream, + }; spec.hash = info->alt; + spec.plus = info->showsign; spec.minus = info->left; spec.width = info->width; - written = handler->hook(buf, sizeof(buf), &spec, args); - if (written > 0) - { - ignore_result(fwrite(buf, 1, written, stream)); - } - return written; + return handler->hook(&data, &spec, args); } /** @@ -145,11 +142,14 @@ static int custom_arginfo(const struct printf_info *info, size_t n, int *argtype */ static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) { - int i, written; - char buf[PRINTF_BUF_LEN]; + int i; const void *args[ARGS_MAX]; printf_hook_spec_t spec; printf_hook_handler_t *handler = printf_hooks[SPEC_TO_INDEX(fmt_spec->name[0])]; + printf_hook_data_t data = { + .base = base, + .pos = pos, + }; for (i = 0; i < handler->numargs; i++) { @@ -165,14 +165,11 @@ static int custom_fmt_cb(Vstr_base *base, size_t pos, Vstr_fmt_spec *fmt_spec) } spec.hash = fmt_spec->fmt_hash; + spec.plus = fmt_spec->fmt_plus; spec.minus = fmt_spec->fmt_minus; spec.width = fmt_spec->fmt_field_width; - written = handler->hook(buf, sizeof(buf), &spec, args); - if (written > 0) - { - vstr_add_buf(base, pos, buf, written); - } + handler->hook(&data, &spec, args); return 1; } @@ -240,6 +237,21 @@ static inline Vstr_conf *get_vstr_conf() return conf; } +/** + * Described in header + */ +size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, + ...) +{ + va_list args; + int written; + + va_start(args, fmt); + written = vstr_add_vfmt(base, pos, fmt, args); + va_end(args); + return written; +} + /** * Wrapper functions for printf and alike */ diff --git a/src/libstrongswan/printf_hook.h b/src/libstrongswan/printf_hook.h index 11fd66ce9..7d3f23bce 100644 --- a/src/libstrongswan/printf_hook.h +++ b/src/libstrongswan/printf_hook.h @@ -24,8 +24,16 @@ typedef struct printf_hook_t printf_hook_t; typedef struct printf_hook_spec_t printf_hook_spec_t; +typedef struct printf_hook_data_t printf_hook_data_t; typedef enum printf_hook_argtype_t printf_hook_argtype_t; +#if !defined(USE_VSTR) && \ + !defined(HAVE_PRINTF_FUNCTION) && \ + !defined(HAVE_PRINTF_SPECIFIER) +/* assume newer glibc register_printf_specifier if none given */ +#define HAVE_PRINTF_SPECIFIER +#endif + #if !defined(USE_VSTR) && \ (defined(HAVE_PRINTF_FUNCTION) || defined(HAVE_PRINTF_SPECIFIER)) @@ -38,6 +46,29 @@ enum printf_hook_argtype_t { PRINTF_HOOK_ARGTYPE_POINTER = PA_POINTER, }; +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Output FILE stream + */ + FILE *stream;; +}; + +/** + * Helper macro to be used in printf hook callbacks. + */ +#define print_in_hook(data, fmt, ...) ({\ + ssize_t _written = fprintf(data->stream, fmt, ##__VA_ARGS__);\ + if (_written < 0)\ + {\ + _written = 0;\ + }\ + _written;\ +}) + #else #include @@ -66,6 +97,37 @@ int vstr_wrapper_vsprintf(char *str, const char *format, va_list ap); int vstr_wrapper_vsnprintf(char *str, size_t size, const char *format, va_list ap); int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap); +#ifdef printf +#undef printf +#endif +#ifdef fprintf +#undef fprintf +#endif +#ifdef sprintf +#undef sprintf +#endif +#ifdef snprintf +#undef snprintf +#endif +#ifdef asprintf +#undef asprintf +#endif +#ifdef vprintf +#undef vprintf +#endif +#ifdef vfprintf +#undef vfprintf +#endif +#ifdef vsprintf +#undef vsprintf +#endif +#ifdef vsnprintf +#undef vsnprintf +#endif +#ifdef vasprintf +#undef vasprintf +#endif + #define printf vstr_wrapper_printf #define fprintf vstr_wrapper_fprintf #define sprintf vstr_wrapper_sprintf @@ -78,36 +140,59 @@ int vstr_wrapper_vasprintf(char **str, const char *format, va_list ap); #define vsnprintf vstr_wrapper_vsnprintf #define vasprintf vstr_wrapper_vasprintf -#endif +/** + * Data to pass to a printf hook. + */ +struct printf_hook_data_t { + + /** + * Base to append printf to + */ + Vstr_base *base; + + /** + * Position in base to write to + */ + size_t pos; +}; /** - * Callback function type for printf hooks. + * Wrapper around vstr_add_vfmt(), avoids having to link all users of + * print_in_hook() against libvstr. * - * @param dst destination buffer - * @param len length of the buffer - * @param spec format specifier - * @param args arguments array + * @param base Vstr_string to add string to + * @param pos position to write to + * @param fmt format string + * @param ... arguments * @return number of characters written */ -typedef int (*printf_hook_function_t)(char *dst, size_t len, - printf_hook_spec_t *spec, - const void *const *args); +size_t vstr_print_in_hook(struct Vstr_base *base, size_t pos, const char *fmt, + ...); /** * Helper macro to be used in printf hook callbacks. - * buf and buflen get modified. */ -#define print_in_hook(buf, buflen, fmt, ...) ({\ - int _written = snprintf(buf, buflen, fmt, ##__VA_ARGS__);\ - if (_written < 0 || _written >= buflen)\ - {\ - _written = buflen - 1;\ - }\ - buf += _written;\ - buflen -= _written;\ +#define print_in_hook(data, fmt, ...) ({\ + size_t _written; \ + _written = vstr_print_in_hook(data->base, data->pos, fmt, ##__VA_ARGS__);\ + data->pos += _written;\ _written;\ }) +#endif + +/** + * Callback function type for printf hooks. + * + * @param data hook data, to pass to print_in_hook() + * @param spec format specifier + * @param args arguments array + * @return number of characters written + */ +typedef int (*printf_hook_function_t)(printf_hook_data_t *data, + printf_hook_spec_t *spec, + const void *const *args); + /** * Properties of the format specifier */ @@ -122,6 +207,11 @@ struct printf_hook_spec_t { */ int minus; + /** + * TRUE if a '+' was used in the format specifier + */ + int plus; + /** * The width as given in the format specifier. */ diff --git a/src/libstrongswan/processing/jobs/callback_job.c b/src/libstrongswan/processing/jobs/callback_job.c index 13f22e69c..a5ddc8ff6 100644 --- a/src/libstrongswan/processing/jobs/callback_job.c +++ b/src/libstrongswan/processing/jobs/callback_job.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2012 Tobias Brunner * Copyright (C) 2007-2011 Martin Willi * Copyright (C) 2011 revosec AG * Hochschule fuer Technik Rapperswil @@ -17,10 +17,9 @@ #include "callback_job.h" -#include - #include #include +#include #include #include @@ -52,42 +51,9 @@ struct private_callback_job_t { callback_job_cleanup_t cleanup; /** - * thread of the job, if running - */ - thread_t *thread; - - /** - * mutex to access jobs interna - */ - mutex_t *mutex; - - /** - * list of associated child jobs - */ - linked_list_t *children; - - /** - * parent of this job, or NULL + * cancel function */ - private_callback_job_t *parent; - - /** - * TRUE if the job got cancelled - */ - bool cancelled; - - /** - * condvar to synchronize the cancellation/destruction of the job - */ - condvar_t *destroyable; - - /** - * semaphore to synchronize the termination of the assigned thread. - * - * separately allocated during cancellation, so that we can wait on it - * without risking that it gets freed too early during destruction. - */ - sem_t *terminated; + callback_job_cancel_t cancel; /** * Priority of this job @@ -95,141 +61,26 @@ struct private_callback_job_t { job_priority_t prio; }; -/** - * unregister a child from its parent, if any. - * note: this->mutex has to be locked - */ -static void unregister(private_callback_job_t *this) -{ - if (this->parent) - { - this->parent->mutex->lock(this->parent->mutex); - if (this->parent->cancelled && !this->cancelled) - { - /* if the parent has been cancelled but we have not yet, we do not - * unregister until we got cancelled by the parent. */ - this->parent->mutex->unlock(this->parent->mutex); - this->destroyable->wait(this->destroyable, this->mutex); - this->parent->mutex->lock(this->parent->mutex); - } - this->parent->children->remove(this->parent->children, this, NULL); - this->parent->mutex->unlock(this->parent->mutex); - this->parent = NULL; - } -} - METHOD(job_t, destroy, void, private_callback_job_t *this) { - this->mutex->lock(this->mutex); - unregister(this); if (this->cleanup) { this->cleanup(this->data); } - if (this->terminated) - { - sem_post(this->terminated); - } - this->children->destroy(this->children); - this->destroyable->destroy(this->destroyable); - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); free(this); } -METHOD(callback_job_t, cancel, void, +METHOD(job_t, execute, job_requeue_t, private_callback_job_t *this) { - callback_job_t *child; - sem_t *terminated = NULL; - - this->mutex->lock(this->mutex); - this->cancelled = TRUE; - /* terminate children */ - while (this->children->get_first(this->children, (void**)&child) == SUCCESS) - { - this->mutex->unlock(this->mutex); - child->cancel(child); - this->mutex->lock(this->mutex); - } - if (this->thread) - { - /* terminate the thread, if there is currently one executing the job. - * we wait for its termination using a semaphore */ - this->thread->cancel(this->thread); - terminated = this->terminated = malloc_thing(sem_t); - sem_init(terminated, 0, 0); - } - else - { - /* if the job is currently queued, it gets terminated later. - * we can't wait, because it might not get executed at all. - * we also unregister the queued job manually from its parent (the - * others get unregistered during destruction) */ - unregister(this); - } - this->destroyable->signal(this->destroyable); - this->mutex->unlock(this->mutex); - - if (terminated) - { - sem_wait(terminated); - sem_destroy(terminated); - free(terminated); - } + return this->callback(this->data); } -METHOD(job_t, execute, void, +METHOD(job_t, cancel, bool, private_callback_job_t *this) { - bool cleanup = FALSE, requeue = FALSE; - - thread_cleanup_push((thread_cleanup_t)destroy, this); - - this->mutex->lock(this->mutex); - this->thread = thread_current(); - this->mutex->unlock(this->mutex); - - while (TRUE) - { - this->mutex->lock(this->mutex); - if (this->cancelled) - { - this->mutex->unlock(this->mutex); - cleanup = TRUE; - break; - } - this->mutex->unlock(this->mutex); - switch (this->callback(this->data)) - { - case JOB_REQUEUE_DIRECT: - continue; - case JOB_REQUEUE_FAIR: - { - requeue = TRUE; - break; - } - case JOB_REQUEUE_NONE: - default: - { - cleanup = TRUE; - break; - } - } - break; - } - this->mutex->lock(this->mutex); - this->thread = NULL; - this->mutex->unlock(this->mutex); - /* manually create a cancellation point to avoid that a cancelled thread - * goes back into the thread pool */ - thread_cancellation_point(); - if (requeue) - { - lib->processor->queue_job(lib->processor, &this->public.job); - } - thread_cleanup_pop(cleanup); + return this->cancel(this->data); } METHOD(job_t, get_priority, job_priority_t, @@ -242,8 +93,8 @@ METHOD(job_t, get_priority, job_priority_t, * Described in header. */ callback_job_t *callback_job_create_with_prio(callback_job_cb_t cb, void *data, - callback_job_cleanup_t cleanup, callback_job_t *parent, - job_priority_t prio) + callback_job_cleanup_t cleanup, callback_job_cancel_t cancel, + job_priority_t prio) { private_callback_job_t *this; @@ -254,24 +105,17 @@ callback_job_t *callback_job_create_with_prio(callback_job_cb_t cb, void *data, .get_priority = _get_priority, .destroy = _destroy, }, - .cancel = _cancel, }, - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .callback = cb, .data = data, .cleanup = cleanup, - .children = linked_list_create(), - .parent = (private_callback_job_t*)parent, - .destroyable = condvar_create(CONDVAR_TYPE_DEFAULT), + .cancel = cancel, .prio = prio, ); - /* register us at parent */ - if (parent) + if (cancel) { - this->parent->mutex->lock(this->parent->mutex); - this->parent->children->insert_last(this->parent->children, this); - this->parent->mutex->unlock(this->parent->mutex); + this->public.job.cancel = _cancel; } return &this->public; @@ -282,8 +126,8 @@ callback_job_t *callback_job_create_with_prio(callback_job_cb_t cb, void *data, */ callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, callback_job_cleanup_t cleanup, - callback_job_t *parent) + callback_job_cancel_t cancel) { - return callback_job_create_with_prio(cb, data, cleanup, parent, + return callback_job_create_with_prio(cb, data, cleanup, cancel, JOB_PRIO_MEDIUM); } diff --git a/src/libstrongswan/processing/jobs/callback_job.h b/src/libstrongswan/processing/jobs/callback_job.h index 3e92b01c0..6f2e39eb8 100644 --- a/src/libstrongswan/processing/jobs/callback_job.h +++ b/src/libstrongswan/processing/jobs/callback_job.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2007-2011 Martin Willi * Copyright (C) 2011 revosec AG * Hochschule fuer Technik Rapperswil @@ -27,33 +28,6 @@ typedef struct callback_job_t callback_job_t; #include #include - -typedef enum job_requeue_t job_requeue_t; - -/** - * Job requeueing policy. - * - * The job requeueing policy defines how a job is handled when the callback - * function returns. - */ -enum job_requeue_t { - - /** - * Do not requeue job, destroy it - */ - JOB_REQUEUE_NONE, - - /** - * Reque the job fairly, meaning it has to requeue as any other job - */ - JOB_REQUEUE_FAIR, - - /** - * Reexecute the job directly, without the need of requeueing it - */ - JOB_REQUEUE_DIRECT, -}; - /** * The callback function to use for the callback job. * @@ -73,10 +47,21 @@ typedef job_requeue_t (*callback_job_cb_t)(void *data); * to supply to the constructor. * * @param data param supplied to job - * @return requeing policy how to requeue the job */ typedef void (*callback_job_cleanup_t)(void *data); +/** + * Cancellation function to use for the callback job. + * + * Optional function to be called when a job has to be canceled. + * + * See job_t.cancel() for details on the return value. + * + * @param data param supplied to job + * @return TRUE if canceled, FALSE to explicitly cancel the thread + */ +typedef bool (*callback_job_cancel_t)(void *data); + /** * Class representing an callback Job. * @@ -91,14 +76,6 @@ struct callback_job_t { */ job_t job; - /** - * Cancel the job's thread and wait for its termination. - * - * This only works reliably for jobs that always use JOB_REQUEUE_FAIR or - * JOB_REQUEUE_DIRECT, otherwise the job may already be destroyed when - * cancel is called. - */ - void (*cancel)(callback_job_t *this); }; /** @@ -106,19 +83,20 @@ struct callback_job_t { * * The cleanup function is called when the job gets destroyed to destroy * the associated data. - * If parent is not NULL, the specified job gets an association. Whenever - * the parent gets cancelled (or runs out), all of its children are cancelled, - * too. + * + * The cancel function is optional and should only be provided if the callback + * function calls potentially blocking functions and/or always returns + * JOB_REQUEUE_DIRECT. * * @param cb callback to call from the processor * @param data user data to supply to callback * @param cleanup destructor for data on destruction, or NULL - * @param parent parent of this job + * @param cancel function to cancel the job, or NULL * @return callback_job_t object */ callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, callback_job_cleanup_t cleanup, - callback_job_t *parent); + callback_job_cancel_t cancel); /** * Creates a callback job, with priority. @@ -128,12 +106,12 @@ callback_job_t *callback_job_create(callback_job_cb_t cb, void *data, * @param cb callback to call from the processor * @param data user data to supply to callback * @param cleanup destructor for data on destruction, or NULL - * @param parent parent of this job + * @param cancel function to cancel the job, or NULL * @param prio job priority * @return callback_job_t object */ callback_job_t *callback_job_create_with_prio(callback_job_cb_t cb, void *data, - callback_job_cleanup_t cleanup, callback_job_t *parent, - job_priority_t prio); + callback_job_cleanup_t cleanup, callback_job_cancel_t cancel, + job_priority_t prio); #endif /** CALLBACK_JOB_H_ @}*/ diff --git a/src/libstrongswan/processing/jobs/job.h b/src/libstrongswan/processing/jobs/job.h index d25cee03e..64454718a 100644 --- a/src/libstrongswan/processing/jobs/job.h +++ b/src/libstrongswan/processing/jobs/job.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -24,6 +25,9 @@ typedef struct job_t job_t; typedef enum job_priority_t job_priority_t; +typedef enum job_status_t job_status_t; +typedef enum job_requeue_type_t job_requeue_type_t; +typedef struct job_requeue_t job_requeue_t; #include @@ -47,19 +51,108 @@ enum job_priority_t { */ extern enum_name_t *job_priority_names; +/** + * Job status + */ +enum job_status_t { + /** The job is queued and has not yet been executed */ + JOB_STATUS_QUEUED = 0, + /** During execution */ + JOB_STATUS_EXECUTING, + /** If the job got canceled */ + JOB_STATUS_CANCELED, + /** The job was executed successfully */ + JOB_STATUS_DONE, +}; + +/** + * How a job is handled after is has been executed. + */ +enum job_requeue_type_t { + /** Do not requeue job, destroy it */ + JOB_REQUEUE_TYPE_NONE = 0, + /** Requeue the job fairly, i.e. it is inserted at the end of the queue */ + JOB_REQUEUE_TYPE_FAIR, + /** Reexecute the job directly, without the need of requeueing it */ + JOB_REQUEUE_TYPE_DIRECT, + /** Rescheduled the job via scheduler_t */ + JOB_REQUEUE_TYPE_SCHEDULE, +}; + +/** + * Job requeueing policy. + * + * The job requeueing policy defines how a job is handled after it has been + * executed. + */ +struct job_requeue_t { + /** How to handle the job after executing it */ + job_requeue_type_t type; + /** How to reschedule the job, if so */ + enum { + JOB_SCHEDULE, + JOB_SCHEDULE_MS, + JOB_SCHEDULE_TV, + } schedule; + /** Time to reschedule the job */ + union { + u_int32_t rel; + timeval_t abs; + } time; +}; + +/** + * Helper macros to easily define requeueing policies. + */ +#define __JOB_REQUEUE(t) (job_requeue_t){ .type = t } +#define JOB_REQUEUE_NONE __JOB_REQUEUE(JOB_REQUEUE_TYPE_NONE) +#define JOB_REQUEUE_FAIR __JOB_REQUEUE(JOB_REQUEUE_TYPE_FAIR) +#define JOB_REQUEUE_DIRECT __JOB_REQUEUE(JOB_REQUEUE_TYPE_DIRECT) +#define __JOB_RESCHEDULE(t, ...) (job_requeue_t){ .type = JOB_REQUEUE_TYPE_SCHEDULE, .schedule = t, { __VA_ARGS__ } } +#define JOB_RESCHEDULE(s) __JOB_RESCHEDULE(JOB_SCHEDULE, .rel = s) +#define JOB_RESCHEDULE_MS(ms) __JOB_RESCHEDULE(JOB_SCHEDULE_MS, .rel = ms) +#define JOB_RESCHEDULE_TV(tv) __JOB_RESCHEDULE(JOB_SCHEDULE_TV, .abs = tv) + /** * Job interface as it is stored in the job queue. */ struct job_t { + /** + * Status of this job, is modified exclusively by the processor/scheduler + */ + job_status_t status; + /** * Execute a job. * * The processing facility executes a job using this method. Jobs are - * one-shot, they destroy themself after execution, so don't use a job - * once it has been executed. + * one-shot, they are destroyed after execution (depending on the return + * value here), so don't use a job once it has been queued. + * + * @return policy how to requeue the job + */ + job_requeue_t (*execute) (job_t *this); + + /** + * Cancel a job. + * + * Implementing this method is optional. It allows potentially blocking + * jobs to be canceled during shutdown. + * + * If no special action is to be taken simply return FALSE then the thread + * executing the job will be canceled. If TRUE is returned the job is + * expected to return from execute() itself (i.e. the thread won't be + * canceled explicitly and can still be joined later). + * Jobs that return FALSE have to make sure they provide the appropriate + * cancellation points. + * + * @note Regular jobs that do not block MUST NOT implement this method. + * @note This method could be called even before execute() has been called. + * + * @return FALSE to cancel the thread, TRUE if canceled otherwise */ - void (*execute) (job_t *this); + bool (*cancel)(job_t *this); /** * Get the priority of a job. @@ -71,10 +164,12 @@ struct job_t { /** * Destroy a job. * - * Is only called whenever a job was not executed (e.g. due daemon shutdown). - * After execution, jobs destroy themself. + * Is called after a job is executed or got canceled. It is also called + * for queued jobs that were never executed. + * + * Use the status of a job to decide what to do during destruction. */ - void (*destroy) (job_t *this); + void (*destroy)(job_t *this); }; #endif /** JOB_H_ @}*/ diff --git a/src/libstrongswan/processing/processor.c b/src/libstrongswan/processing/processor.c index 222f1a535..5b7fd467c 100644 --- a/src/libstrongswan/processing/processor.c +++ b/src/libstrongswan/processing/processor.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2011 revosec AG - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -58,7 +58,7 @@ struct private_processor_t { /** * All threads managed in the pool (including threads that have been - * cancelled, this allows to join them during destruction) + * canceled, this allows to join them later), as worker_thread_t */ linked_list_t *threads; @@ -72,11 +72,6 @@ struct private_processor_t { */ int prio_threads[JOB_PRIO_MAX]; - /** - * Priority of the job executed by a thread - */ - thread_value_t *priority; - /** * access to job lists is locked through this mutex */ @@ -93,39 +88,71 @@ struct private_processor_t { condvar_t *thread_terminated; }; -static void process_jobs(private_processor_t *this); +/** + * Worker thread + */ +typedef struct { + + /** + * Reference to the processor + */ + private_processor_t *processor; + + /** + * The actual thread + */ + thread_t *thread; + + /** + * Job currently being executed by this worker thread + */ + job_t *job; + + /** + * Priority of the current job + */ + job_priority_t priority; + +} worker_thread_t; + +static void process_jobs(worker_thread_t *worker); /** * restart a terminated thread */ -static void restart(private_processor_t *this) +static void restart(worker_thread_t *worker) { - thread_t *thread; + private_processor_t *this = worker->processor; DBG2(DBG_JOB, "terminated worker thread %.2u", thread_current_id()); - /* respawn thread if required */ this->mutex->lock(this->mutex); - if (this->desired_threads < this->total_threads || - (thread = thread_create((thread_main_t)process_jobs, this)) == NULL) - { - this->total_threads--; - this->thread_terminated->signal(this->thread_terminated); - } - else + /* cleanup worker thread */ + this->working_threads[worker->priority]--; + worker->job->status = JOB_STATUS_CANCELED; + worker->job->destroy(worker->job); + worker->job = NULL; + + /* respawn thread if required */ + if (this->desired_threads >= this->total_threads) { - this->threads->insert_last(this->threads, thread); + worker_thread_t *new_worker; + + INIT(new_worker, + .processor = this, + ); + new_worker->thread = thread_create((thread_main_t)process_jobs, + new_worker); + if (new_worker->thread) + { + this->threads->insert_last(this->threads, new_worker); + this->mutex->unlock(this->mutex); + return; + } + free(new_worker); } - this->mutex->unlock(this->mutex); -} - -/** - * Decrement working thread count of a priority class - */ -static void decrement_working_threads(private_processor_t *this) -{ - this->mutex->lock(this->mutex); - this->working_threads[(intptr_t)this->priority->get(this->priority)]--; + this->total_threads--; + this->thread_terminated->signal(this->thread_terminated); this->mutex->unlock(this->mutex); } @@ -147,9 +174,11 @@ static u_int get_idle_threads_nolock(private_processor_t *this) /** * Process queued jobs, called by the worker threads */ -static void process_jobs(private_processor_t *this) +static void process_jobs(worker_thread_t *worker) { - /* worker threads are not cancellable by default */ + private_processor_t *this = worker->processor; + + /* worker threads are not cancelable by default */ thread_cancelability(FALSE); DBG2(DBG_JOB, "started worker thread %.2u", thread_current_id()); @@ -157,7 +186,6 @@ static void process_jobs(private_processor_t *this) this->mutex->lock(this->mutex); while (this->desired_threads >= this->total_threads) { - job_t *job = NULL; int i, reserved = 0, idle; idle = get_idle_threads_nolock(this); @@ -176,27 +204,80 @@ static void process_jobs(private_processor_t *this) reserved += this->prio_threads[i] - this->working_threads[i]; } if (this->jobs[i]->remove_first(this->jobs[i], - (void**)&job) == SUCCESS) + (void**)&worker->job) == SUCCESS) { + job_requeue_t requeue; + this->working_threads[i]++; + worker->job->status = JOB_STATUS_EXECUTING; + worker->priority = i; this->mutex->unlock(this->mutex); - this->priority->set(this->priority, (void*)(intptr_t)i); - /* terminated threads are restarted to get a constant pool */ - thread_cleanup_push((thread_cleanup_t)restart, this); - thread_cleanup_push((thread_cleanup_t)decrement_working_threads, - this); - job->execute(job); - thread_cleanup_pop(FALSE); + /* canceled threads are restarted to get a constant pool */ + thread_cleanup_push((thread_cleanup_t)restart, worker); + while (TRUE) + { + requeue = worker->job->execute(worker->job); + if (requeue.type != JOB_REQUEUE_TYPE_DIRECT) + { + break; + } + else if (!worker->job->cancel) + { /* only allow cancelable jobs to requeue directly */ + requeue.type = JOB_REQUEUE_TYPE_FAIR; + break; + } + } thread_cleanup_pop(FALSE); this->mutex->lock(this->mutex); this->working_threads[i]--; + if (worker->job->status == JOB_STATUS_CANCELED) + { /* job was canceled via a custom cancel() method or did not + * use JOB_REQUEUE_TYPE_DIRECT */ + worker->job->destroy(worker->job); + break; + } + switch (requeue.type) + { + case JOB_REQUEUE_TYPE_NONE: + worker->job->status = JOB_STATUS_DONE; + worker->job->destroy(worker->job); + break; + case JOB_REQUEUE_TYPE_FAIR: + worker->job->status = JOB_STATUS_QUEUED; + this->jobs[i]->insert_last(this->jobs[i], + worker->job); + this->job_added->signal(this->job_added); + break; + case JOB_REQUEUE_TYPE_SCHEDULE: + /* scheduler_t does not hold its lock when queeuing jobs + * so this should be safe without unlocking our mutex */ + switch (requeue.schedule) + { + case JOB_SCHEDULE: + lib->scheduler->schedule_job(lib->scheduler, + worker->job, requeue.time.rel); + break; + case JOB_SCHEDULE_MS: + lib->scheduler->schedule_job_ms(lib->scheduler, + worker->job, requeue.time.rel); + break; + case JOB_SCHEDULE_TV: + lib->scheduler->schedule_job_tv(lib->scheduler, + worker->job, requeue.time.abs); + break; + } + break; + default: + break; + } break; } } - if (!job) + if (!worker->job) { this->job_added->wait(this->job_added, this->mutex); } + worker->job = NULL; } this->total_threads--; this->thread_terminated->signal(this->thread_terminated); @@ -266,6 +347,8 @@ METHOD(processor_t, queue_job, void, job_priority_t prio; prio = sane_prio(job->get_priority(job)); + job->status = JOB_STATUS_QUEUED; + this->mutex->lock(this->mutex); this->jobs[prio]->insert_last(this->jobs[prio], job); this->job_added->signal(this->job_added); @@ -278,19 +361,26 @@ METHOD(processor_t, set_threads, void, this->mutex->lock(this->mutex); if (count > this->total_threads) { /* increase thread count */ + worker_thread_t *worker; int i; - thread_t *current; this->desired_threads = count; DBG1(DBG_JOB, "spawning %d worker threads", count - this->total_threads); for (i = this->total_threads; i < count; i++) { - current = thread_create((thread_main_t)process_jobs, this); - if (current) + INIT(worker, + .processor = this, + ); + worker->thread = thread_create((thread_main_t)process_jobs, worker); + if (worker->thread) { - this->threads->insert_last(this->threads, current); + this->threads->insert_last(this->threads, worker); this->total_threads++; } + else + { + free(worker); + } } } else if (count < this->total_threads) @@ -301,26 +391,49 @@ METHOD(processor_t, set_threads, void, this->mutex->unlock(this->mutex); } -METHOD(processor_t, destroy, void, +METHOD(processor_t, cancel, void, private_processor_t *this) { - thread_t *current; - int i; + enumerator_t *enumerator; + worker_thread_t *worker; - set_threads(this, 0); this->mutex->lock(this->mutex); + this->desired_threads = 0; + /* cancel potentially blocking jobs */ + enumerator = this->threads->create_enumerator(this->threads); + while (enumerator->enumerate(enumerator, (void**)&worker)) + { + if (worker->job && worker->job->cancel) + { + worker->job->status = JOB_STATUS_CANCELED; + if (!worker->job->cancel(worker->job)) + { /* job requests to be canceled explicitly, otherwise we assume + * the thread terminates itself and can be joined */ + worker->thread->cancel(worker->thread); + } + } + } + enumerator->destroy(enumerator); while (this->total_threads > 0) { this->job_added->broadcast(this->job_added); this->thread_terminated->wait(this->thread_terminated, this->mutex); } while (this->threads->remove_first(this->threads, - (void**)¤t) == SUCCESS) + (void**)&worker) == SUCCESS) { - current->join(current); + worker->thread->join(worker->thread); + free(worker); } this->mutex->unlock(this->mutex); - this->priority->destroy(this->priority); +} + +METHOD(processor_t, destroy, void, + private_processor_t *this) +{ + int i; + + cancel(this); this->thread_terminated->destroy(this->thread_terminated); this->job_added->destroy(this->job_added); this->mutex->destroy(this->mutex); @@ -348,10 +461,10 @@ processor_t *processor_create() .get_job_load = _get_job_load, .queue_job = _queue_job, .set_threads = _set_threads, + .cancel = _cancel, .destroy = _destroy, }, .threads = linked_list_create(), - .priority = thread_value_create(NULL), .mutex = mutex_create(MUTEX_TYPE_DEFAULT), .job_added = condvar_create(CONDVAR_TYPE_DEFAULT), .thread_terminated = condvar_create(CONDVAR_TYPE_DEFAULT), diff --git a/src/libstrongswan/processing/processor.h b/src/libstrongswan/processing/processor.h index 5db42c04c..94860f5d3 100644 --- a/src/libstrongswan/processing/processor.h +++ b/src/libstrongswan/processing/processor.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2007 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -51,7 +52,7 @@ struct processor_t { /** * Get the number of threads currently working, per priority class. * - * @param prioritiy to check + * @param priority to check * @return number of threads in priority working */ u_int (*get_working_threads)(processor_t *this, job_priority_t prio); @@ -78,13 +79,20 @@ struct processor_t { * * If the number of threads is smaller than number of currently running * threads, thread count is decreased. Use 0 to disable the processor. - * This call blocks if it decreases thread count until threads have - * terminated, so make sure there are not too many blocking jobs. + * + * This call does not block and wait for threads to terminate if the number + * of threads is reduced. Instead use cancel() for that during shutdown. * * @param count number of threads to allocate */ void (*set_threads)(processor_t *this, u_int count); + /** + * Sets the number of threads to 0 and cancels all blocking jobs, then waits + * for all threads to be terminated. + */ + void (*cancel)(processor_t *this); + /** * Destroy a processor object. */ diff --git a/src/libstrongswan/processing/scheduler.c b/src/libstrongswan/processing/scheduler.c index f3cc1164a..c97dbc4be 100644 --- a/src/libstrongswan/processing/scheduler.c +++ b/src/libstrongswan/processing/scheduler.c @@ -67,11 +67,6 @@ struct private_scheduler_t { */ scheduler_t public; - /** - * Job which queues scheduled jobs to the processor. - */ - callback_job_t *job; - /** * The heap in which the events are stored. */ @@ -250,6 +245,7 @@ METHOD(scheduler_t, schedule_job_tv, void, event = malloc_thing(event_t); event->job = job; + event->job->status = JOB_STATUS_QUEUED; event->time = tv; this->mutex->lock(this->mutex); @@ -308,7 +304,6 @@ METHOD(scheduler_t, destroy, void, private_scheduler_t *this) { event_t *event; - this->job->cancel(this->job); this->condvar->destroy(this->condvar); this->mutex->destroy(this->mutex); while ((event = remove_event(this)) != NULL) @@ -325,6 +320,7 @@ METHOD(scheduler_t, destroy, void, scheduler_t * scheduler_create() { private_scheduler_t *this; + callback_job_t *job; INIT(this, .public = { @@ -341,9 +337,9 @@ scheduler_t * scheduler_create() this->heap = (event_t**)calloc(this->heap_size + 1, sizeof(event_t*)); - this->job = callback_job_create_with_prio((callback_job_cb_t)schedule, - this, NULL, NULL, JOB_PRIO_CRITICAL); - lib->processor->queue_job(lib->processor, (job_t*)this->job); + job = callback_job_create_with_prio((callback_job_cb_t)schedule, this, + NULL, return_false, JOB_PRIO_CRITICAL); + lib->processor->queue_job(lib->processor, (job_t*)job); return &this->public; } diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c index b1bcf1b2d..b19b962e6 100644 --- a/src/libstrongswan/selectors/traffic_selector.c +++ b/src/libstrongswan/selectors/traffic_selector.c @@ -179,8 +179,8 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts /** * Described in header. */ -int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, - const void *const *args) +int traffic_selector_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args) { private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0])); linked_list_t *list = *((linked_list_t**)(args[0])); @@ -195,7 +195,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec if (this == NULL) { - return print_in_hook(dst, len, "(null)"); + return print_in_hook(data, "(null)"); } if (spec->hash) @@ -204,7 +204,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec while (enumerator->enumerate(enumerator, (void**)&this)) { /* call recursivly */ - written += print_in_hook(dst, len, "%R ", this); + written += print_in_hook(data, "%R ", this); } enumerator->destroy(enumerator); return written; @@ -216,7 +216,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec memeq(this->from, from, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16) && memeq(this->to, to, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16)) { - written += print_in_hook(dst, len, "dynamic"); + written += print_in_hook(data, "dynamic"); } else { @@ -238,11 +238,11 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec { inet_ntop(AF_INET6, &this->to6, to_str, sizeof(to_str)); } - written += print_in_hook(dst, len, "%s..%s", from_str, to_str); + written += print_in_hook(data, "%s..%s", from_str, to_str); } else { - written += print_in_hook(dst, len, "%s/%d", from_str, this->netbits); + written += print_in_hook(data, "%s/%d", from_str, this->netbits); } } @@ -255,7 +255,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec return written; } - written += print_in_hook(dst, len, "["); + written += print_in_hook(data, "["); /* build protocol string */ if (has_proto) @@ -264,18 +264,18 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec if (proto) { - written += print_in_hook(dst, len, "%s", proto->p_name); + written += print_in_hook(data, "%s", proto->p_name); serv_proto = proto->p_name; } else { - written += print_in_hook(dst, len, "%d", this->protocol); + written += print_in_hook(data, "%d", this->protocol); } } if (has_proto && has_ports) { - written += print_in_hook(dst, len, "/"); + written += print_in_hook(data, "/"); } /* build port string */ @@ -287,20 +287,20 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec if (serv) { - written += print_in_hook(dst, len, "%s", serv->s_name); + written += print_in_hook(data, "%s", serv->s_name); } else { - written += print_in_hook(dst, len, "%d", this->from_port); + written += print_in_hook(data, "%d", this->from_port); } } else { - written += print_in_hook(dst, len, "%d-%d", this->from_port, this->to_port); + written += print_in_hook(data, "%d-%d", this->from_port, this->to_port); } } - written += print_in_hook(dst, len, "]"); + written += print_in_hook(data, "]"); return written; } @@ -310,6 +310,10 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec */ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other) { + if (this->dynamic || other->dynamic) + { /* no set_address() applied, TS has no subset */ + return NULL; + } if (this->type == other->type && (this->protocol == other->protocol || this->protocol == 0 || other->protocol == 0)) { @@ -367,7 +371,6 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ /* we have a match in protocol, port, and address: return it... */ new_ts = traffic_selector_create(protocol, this->type, from_port, to_port); - new_ts->dynamic = this->dynamic || other->dynamic; memcpy(new_ts->from, from, size); memcpy(new_ts->to, to, size); calc_netbits(new_ts); @@ -510,7 +513,7 @@ METHOD(traffic_selector_t, is_dynamic, bool, METHOD(traffic_selector_t, set_address, void, private_traffic_selector_t *this, host_t *host) { - if (this->dynamic) + if (is_host(this, NULL)) { this->type = host->get_family(host) == AF_INET ? TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE; @@ -528,6 +531,7 @@ METHOD(traffic_selector_t, set_address, void, memcpy(this->to, from.ptr, from.len); this->netbits = from.len * 8; } + this->dynamic = FALSE; } } @@ -571,7 +575,7 @@ METHOD(traffic_selector_t, includes, bool, return FALSE; } -METHOD(traffic_selector_t, to_subnet, void, +METHOD(traffic_selector_t, to_subnet, bool, private_traffic_selector_t *this, host_t **net, u_int8_t *mask) { /* there is no way to do this cleanly, as the address range may @@ -597,7 +601,7 @@ METHOD(traffic_selector_t, to_subnet, void, break; default: /* unreachable */ - return; + return FALSE; } net_chunk.ptr = malloc(net_chunk.len); @@ -616,6 +620,8 @@ METHOD(traffic_selector_t, to_subnet, void, *net = host_create_from_chunk(family, net_chunk, port); chunk_free(&net_chunk); + + return this->netbits != NON_SUBNET_ADDRESS_RANGE; } METHOD(traffic_selector_t, clone_, traffic_selector_t*, @@ -735,66 +741,36 @@ traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type, traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits, u_int8_t protocol, u_int16_t port) { - private_traffic_selector_t *this = traffic_selector_create(protocol, 0, 0, 65535); + private_traffic_selector_t *this; + chunk_t from; + + this = traffic_selector_create(protocol, 0, 0, 65535); switch (net->get_family(net)) { case AF_INET: - { - chunk_t from; - this->type = TS_IPV4_ADDR_RANGE; - from = net->get_address(net); - memcpy(this->from, from.ptr, from.len); - if (this->from4[0] == 0) - { - /* use /0 for 0.0.0.0 */ - this->to4[0] = ~0; - this->netbits = 0; - } - else - { - calc_range(this, netbits); - } break; - } case AF_INET6: - { - chunk_t from; - this->type = TS_IPV6_ADDR_RANGE; - from = net->get_address(net); - memcpy(this->from, from.ptr, from.len); - if (this->from6[0] == 0 && this->from6[1] == 0 && - this->from6[2] == 0 && this->from6[3] == 0) - { - /* use /0 for ::0 */ - this->to6[0] = ~0; - this->to6[1] = ~0; - this->to6[2] = ~0; - this->to6[3] = ~0; - this->netbits = 0; - } - else - { - calc_range(this, netbits); - } break; - } default: - { net->destroy(net); free(this); return NULL; - } } + from = net->get_address(net); + memcpy(this->from, from.ptr, from.len); + netbits = min(netbits, this->type == TS_IPV4_ADDR_RANGE ? 32 : 128); + calc_range(this, netbits); if (port) { this->from_port = port; this->to_port = port; } net->destroy(net); - return (&this->public); + + return &this->public; } /* diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h index 257da3f24..7a81521e9 100644 --- a/src/libstrongswan/selectors/traffic_selector.h +++ b/src/libstrongswan/selectors/traffic_selector.h @@ -203,8 +203,9 @@ struct traffic_selector_t { * * @param net converted subnet (has to be freed) * @param mask converted net mask + * @return TRUE if traffic selector matches exactly to the subnet */ - void (*to_subnet) (traffic_selector_t *this, host_t **net, u_int8_t *mask); + bool (*to_subnet) (traffic_selector_t *this, host_t **net, u_int8_t *mask); /** * Destroys the ts object @@ -309,7 +310,7 @@ traffic_selector_t *traffic_selector_create_dynamic(u_int8_t protocol, * With the #-specifier, arguments are: * linked_list_t *list containing traffic_selector_t* */ -int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, - const void *const *args); +int traffic_selector_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args); #endif /** TRAFFIC_SELECTOR_H_ @}*/ diff --git a/src/libstrongswan/settings.c b/src/libstrongswan/settings.c index b26fbebb4..8977cd9ed 100644 --- a/src/libstrongswan/settings.c +++ b/src/libstrongswan/settings.c @@ -1117,14 +1117,21 @@ static bool load_files_internal(private_settings_t *this, section_t *parent, char *pattern, bool merge) { char *text; - linked_list_t *contents = linked_list_create(); - section_t *section = section_create(NULL); + linked_list_t *contents; + section_t *section; if (pattern == NULL) { +#ifdef STRONGSWAN_CONF pattern = STRONGSWAN_CONF; +#else + return FALSE; +#endif } + contents = linked_list_create(); + section = section_create(NULL); + if (!parse_files(contents, NULL, 0, pattern, section)) { contents->destroy_function(contents, (void*)free); diff --git a/src/libstrongswan/settings.h b/src/libstrongswan/settings.h index a864779f1..c8b50d008 100644 --- a/src/libstrongswan/settings.h +++ b/src/libstrongswan/settings.h @@ -189,7 +189,7 @@ struct settings_t { * @param key key including sections, printf style format * @param def value returned if key not found * @param ... argument list for key - * @return value of the key + * @return value of the key (in seconds) */ u_int32_t (*get_time)(settings_t *this, char *key, u_int32_t def, ...); diff --git a/src/libstrongswan/threading/mutex.c b/src/libstrongswan/threading/mutex.c index 3bdb3bf29..2ef918a28 100644 --- a/src/libstrongswan/threading/mutex.c +++ b/src/libstrongswan/threading/mutex.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -73,9 +73,9 @@ struct private_r_mutex_t { pthread_t thread; /** - * times we have locked the lock, stored per thread + * times the current thread locked the mutex */ - pthread_key_t times; + u_int times; }; /** @@ -127,35 +127,24 @@ METHOD(mutex_t, lock_r, void, { pthread_t self = pthread_self(); - if (this->thread == self) + if (pthread_equal(this->thread, self)) { - uintptr_t times; - - /* times++ */ - times = (uintptr_t)pthread_getspecific(this->times); - pthread_setspecific(this->times, (void*)times + 1); + this->times++; } else { lock(&this->generic); this->thread = self; - /* times = 1 */ - pthread_setspecific(this->times, (void*)1); + this->times = 1; } } METHOD(mutex_t, unlock_r, void, private_r_mutex_t *this) { - uintptr_t times; - - /* times-- */ - times = (uintptr_t)pthread_getspecific(this->times); - pthread_setspecific(this->times, (void*)--times); - - if (times == 0) + if (--this->times == 0) { - this->thread = 0; + memset(&this->thread, 0, sizeof(this->thread)); unlock(&this->generic); } } @@ -173,7 +162,6 @@ METHOD(mutex_t, mutex_destroy_r, void, { profiler_cleanup(&this->generic.profile); pthread_mutex_destroy(&this->generic.mutex); - pthread_key_delete(this->times); free(this); } @@ -200,7 +188,6 @@ mutex_t *mutex_create(mutex_type_t type) ); pthread_mutex_init(&this->generic.mutex, NULL); - pthread_key_create(&this->times, NULL); profiler_init(&this->generic.profile); return &this->generic.public; @@ -233,11 +220,15 @@ METHOD(condvar_t, wait_, void, if (mutex->recursive) { private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + u_int times; + /* keep track of the number of times this thread locked the mutex */ + times = recursive->times; /* mutex owner gets cleared during condvar wait */ - recursive->thread = 0; + memset(&recursive->thread, 0, sizeof(recursive->thread)); pthread_cond_wait(&this->condvar, &mutex->mutex); recursive->thread = pthread_self(); + recursive->times = times; } else { @@ -262,11 +253,14 @@ METHOD(condvar_t, timed_wait_abs, bool, if (mutex->recursive) { private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + u_int times; - recursive->thread = 0; + times = recursive->times; + memset(&recursive->thread, 0, sizeof(recursive->thread)); timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, &ts) == ETIMEDOUT; recursive->thread = pthread_self(); + recursive->times = times; } else { diff --git a/src/libstrongswan/threading/rwlock.c b/src/libstrongswan/threading/rwlock.c index 15dc0b334..7097a8e8c 100644 --- a/src/libstrongswan/threading/rwlock.c +++ b/src/libstrongswan/threading/rwlock.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2009 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -21,11 +21,14 @@ #include #include "rwlock.h" +#include "rwlock_condvar.h" +#include "thread.h" #include "condvar.h" #include "mutex.h" #include "lock_profiler.h" typedef struct private_rwlock_t private_rwlock_t; +typedef struct private_rwlock_condvar_t private_rwlock_condvar_t; /** * private data of rwlock @@ -72,9 +75,9 @@ struct private_rwlock_t { u_int reader_count; /** - * current writer thread, if any + * TRUE, if a writer is holding the lock currently */ - pthread_t writer; + bool writer; #endif /* HAVE_PTHREAD_RWLOCK_INIT */ @@ -84,6 +87,27 @@ struct private_rwlock_t { lock_profile_t profile; }; +/** + * private data of condvar + */ +struct private_rwlock_condvar_t { + + /** + * public interface + */ + rwlock_condvar_t public; + + /** + * mutex used to implement rwlock condvar + */ + mutex_t *mutex; + + /** + * regular condvar to implement rwlock condvar + */ + condvar_t *condvar; +}; + #ifdef HAVE_PTHREAD_RWLOCK_INIT @@ -175,37 +199,81 @@ rwlock_t *rwlock_create(rwlock_type_t type) /** * This implementation of the rwlock_t interface uses mutex_t and condvar_t - * primitives, if the pthread_rwlock_* group of functions is not available. + * primitives, if the pthread_rwlock_* group of functions is not available or + * don't allow recursive locking for readers. * * The following constraints are enforced: * - Multiple readers can hold the lock at the same time. * - Only a single writer can hold the lock at any given time. * - A writer must block until all readers have released the lock before * obtaining the lock exclusively. - * - Readers that arrive while a writer is waiting to acquire the lock will - * block until after the writer has obtained and released the lock. + * - Readers that don't hold any read lock and arrive while a writer is + * waiting to acquire the lock will block until after the writer has + * obtained and released the lock. * These constraints allow for read sharing, prevent write sharing, prevent - * read-write sharing and prevent starvation of writers by a steady stream - * of incoming readers. Reader starvation is not prevented (this could happen - * if there are more writers than readers). + * read-write sharing and (largely) prevent starvation of writers by a steady + * stream of incoming readers. Reader starvation is not prevented (this could + * happen if there are more writers than readers). * - * The implementation does not support recursive locking and readers must not - * acquire the lock exclusively at the same time and vice-versa (this is not - * checked or enforced so behave yourself to prevent deadlocks). + * The implementation supports recursive locking of the read lock but not of + * the write lock. Readers must not acquire the lock exclusively at the same + * time and vice-versa (this is not checked or enforced so behave yourself to + * prevent deadlocks). + * + * Since writers are preferred a thread currently holding the read lock that + * tries to acquire the read lock recursively while a writer is waiting would + * result in a deadlock. In order to avoid having to use a thread-specific + * value for each rwlock_t (or a list of threads) to keep track if a thread + * already acquired the read lock we use a single thread-specific value for all + * rwlock_t objects that keeps track of how many read locks a thread currently + * holds. Preferring readers that already hold ANY read locks prevents this + * deadlock while it still largely avoids writer starvation (for locks that can + * only be acquired while holding another read lock this will obviously not + * work). */ +/** + * Keep track of how many read locks a thread holds. + */ +static pthread_key_t is_reader; + +/** + * Only initialize the read lock counter once. + */ +static pthread_once_t is_reader_initialized = PTHREAD_ONCE_INIT; + +/** + * Initialize the read lock counter. + */ +static void initialize_is_reader() +{ + pthread_key_create(&is_reader, NULL); +} + METHOD(rwlock_t, read_lock, void, private_rwlock_t *this) { + uintptr_t reading; + + reading = (uintptr_t)pthread_getspecific(is_reader); profiler_start(&this->profile); this->mutex->lock(this->mutex); - while (this->writer || this->waiting_writers) + if (!this->writer && reading > 0) { - this->readers->wait(this->readers, this->mutex); + /* directly allow threads that hold ANY read locks, to avoid a deadlock + * caused by preferring writers in the loop below */ + } + else + { + while (this->writer || this->waiting_writers) + { + this->readers->wait(this->readers, this->mutex); + } } this->reader_count++; profiler_end(&this->profile); this->mutex->unlock(this->mutex); + pthread_setspecific(is_reader, (void*)(reading + 1)); } METHOD(rwlock_t, write_lock, void, @@ -219,7 +287,7 @@ METHOD(rwlock_t, write_lock, void, this->writers->wait(this->writers, this->mutex); } this->waiting_writers--; - this->writer = pthread_self(); + this->writer = TRUE; profiler_end(&this->profile); this->mutex->unlock(this->mutex); } @@ -231,8 +299,7 @@ METHOD(rwlock_t, try_write_lock, bool, this->mutex->lock(this->mutex); if (!this->writer && !this->reader_count) { - res = TRUE; - this->writer = pthread_self(); + res = this->writer = TRUE; } this->mutex->unlock(this->mutex); return res; @@ -242,9 +309,20 @@ METHOD(rwlock_t, unlock, void, private_rwlock_t *this) { this->mutex->lock(this->mutex); - if (this->writer == pthread_self()) + if (this->writer) + { + this->writer = FALSE; + } + else + { + uintptr_t reading; + + this->reader_count--; + reading = (uintptr_t)pthread_getspecific(is_reader); + pthread_setspecific(is_reader, (void*)(reading - 1)); + } + if (!this->reader_count) { - this->writer = 0; if (this->waiting_writers) { this->writers->signal(this->writers); @@ -254,14 +332,6 @@ METHOD(rwlock_t, unlock, void, this->readers->broadcast(this->readers); } } - else - { - this->reader_count--; - if (!this->reader_count) - { - this->writers->signal(this->writers); - } - } this->mutex->unlock(this->mutex); } @@ -280,6 +350,8 @@ METHOD(rwlock_t, destroy, void, */ rwlock_t *rwlock_create(rwlock_type_t type) { + pthread_once(&is_reader_initialized, initialize_is_reader); + switch (type) { case RWLOCK_TYPE_DEFAULT: @@ -309,3 +381,110 @@ rwlock_t *rwlock_create(rwlock_type_t type) #endif /* HAVE_PTHREAD_RWLOCK_INIT */ + +METHOD(rwlock_condvar_t, wait_, void, + private_rwlock_condvar_t *this, rwlock_t *lock) +{ + /* at this point we have the write lock locked, to make signals more + * predictable we try to prevent other threads from signaling by acquiring + * the mutex while we still hold the write lock (this assumes they will + * hold the write lock themselves when signaling, which is not mandatory) */ + this->mutex->lock(this->mutex); + /* unlock the rwlock and wait for a signal */ + lock->unlock(lock); + /* if the calling thread enabled thread cancelability we want to replicate + * the behavior of the regular condvar, i.e. the lock will be held again + * before executing cleanup functions registered by the calling thread */ + thread_cleanup_push((thread_cleanup_t)lock->write_lock, lock); + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + this->condvar->wait(this->condvar, this->mutex); + /* we release the mutex to allow other threads into the condvar (might even + * be required so we can acquire the lock again below) */ + thread_cleanup_pop(TRUE); + /* finally we reacquire the lock we held previously */ + thread_cleanup_pop(TRUE); +} + +METHOD(rwlock_condvar_t, timed_wait_abs, bool, + private_rwlock_condvar_t *this, rwlock_t *lock, timeval_t time) +{ + bool timed_out; + + /* see wait() above for details on what is going on here */ + this->mutex->lock(this->mutex); + lock->unlock(lock); + thread_cleanup_push((thread_cleanup_t)lock->write_lock, lock); + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + timed_out = this->condvar->timed_wait_abs(this->condvar, this->mutex, time); + thread_cleanup_pop(TRUE); + thread_cleanup_pop(!timed_out); + return timed_out; +} + +METHOD(rwlock_condvar_t, timed_wait, bool, + private_rwlock_condvar_t *this, rwlock_t *lock, u_int timeout) +{ + timeval_t tv; + u_int s, ms; + + time_monotonic(&tv); + + s = timeout / 1000; + ms = timeout % 1000; + + tv.tv_sec += s; + tv.tv_usec += ms * 1000; + + if (tv.tv_usec > 1000000 /* 1s */) + { + tv.tv_usec -= 1000000; + tv.tv_sec++; + } + return timed_wait_abs(this, lock, tv); +} + +METHOD(rwlock_condvar_t, signal_, void, + private_rwlock_condvar_t *this) +{ + this->mutex->lock(this->mutex); + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); +} + +METHOD(rwlock_condvar_t, broadcast, void, + private_rwlock_condvar_t *this) +{ + this->mutex->lock(this->mutex); + this->condvar->broadcast(this->condvar); + this->mutex->unlock(this->mutex); +} + +METHOD(rwlock_condvar_t, condvar_destroy, void, + private_rwlock_condvar_t *this) +{ + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); + free(this); +} + +/* + * see header file + */ +rwlock_condvar_t *rwlock_condvar_create() +{ + private_rwlock_condvar_t *this; + + INIT(this, + .public = { + .wait = _wait_, + .timed_wait = _timed_wait, + .timed_wait_abs = _timed_wait_abs, + .signal = _signal_, + .broadcast = _broadcast, + .destroy = _condvar_destroy, + }, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + ); + return &this->public; +} diff --git a/src/libstrongswan/threading/rwlock_condvar.h b/src/libstrongswan/threading/rwlock_condvar.h new file mode 100644 index 000000000..2b40c3fc6 --- /dev/null +++ b/src/libstrongswan/threading/rwlock_condvar.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup rwlock_condvar rwlock_condvar + * @{ @ingroup threading + */ + +#ifndef RWLOCK_CONDVAR_H_ +#define RWLOCK_CONDVAR_H_ + +typedef struct rwlock_condvar_t rwlock_condvar_t; + +#include "rwlock.h" + +/** + * A special condvar implementation that can be used in conjunction + * with rwlock_t (the write lock to be precise). + * + * @note The implementation does not verify that the current thread actually + * holds the write lock and not the read lock, so watch out. + */ +struct rwlock_condvar_t { + + /** + * Wait on a condvar until it gets signalized. + * + * @param lock lock to release while waiting (write lock) + */ + void (*wait)(rwlock_condvar_t *this, rwlock_t *lock); + + /** + * Wait on a condvar until it gets signalized, or times out. + * + * @param lock lock to release while waiting (write lock) + * @param timeout timeout im ms + * @return TRUE if timed out, FALSE otherwise + */ + bool (*timed_wait)(rwlock_condvar_t *this, rwlock_t *lock, u_int timeout); + + /** + * Wait on a condvar until it gets signalized, or times out. + * + * The passed timeval should be calculated based on the time_monotonic() + * function. + * + * @param lock lock to release while waiting (write lock) + * @param tv absolute time until timeout + * @return TRUE if timed out, FALSE otherwise + */ + bool (*timed_wait_abs)(rwlock_condvar_t *this, rwlock_t *lock, + timeval_t tv); + + /** + * Wake up a single thread in a condvar. + */ + void (*signal)(rwlock_condvar_t *this); + + /** + * Wake up all threads in a condvar. + */ + void (*broadcast)(rwlock_condvar_t *this); + + /** + * Destroy a condvar and free its resources. + */ + void (*destroy)(rwlock_condvar_t *this); +}; + +/** + * Create a condvar instance. + * + * @return condvar instance + */ +rwlock_condvar_t *rwlock_condvar_create(); + +#endif /** RWLOCK_CONDVAR_H_ @} */ + diff --git a/src/libstrongswan/threading/semaphore.c b/src/libstrongswan/threading/semaphore.c new file mode 100644 index 000000000..b785ff944 --- /dev/null +++ b/src/libstrongswan/threading/semaphore.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#if defined(HAVE_CLOCK_GETTIME) && \ + (defined(HAVE_CONDATTR_CLOCK_MONOTONIC) || \ + defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)) +/* if we use MONOTONIC times, we can't use POSIX_SEMAPHORES since they use + * times based on CLOCK_REALTIME */ +#undef HAVE_SEM_TIMEDWAIT +#endif /* HAVE_CLOCK_GETTIME && ... */ + +#ifdef HAVE_SEM_TIMEDWAIT +#include +#else /* !HAVE_SEM_TIMEDWAIT */ +#include +#endif /* HAVE_SEM_TIMEDWAIT */ + +#include "semaphore.h" + +typedef struct private_semaphore_t private_semaphore_t; + +/** + * private data of a semaphore + */ +struct private_semaphore_t { + /** + * public interface + */ + semaphore_t public; + +#ifdef HAVE_SEM_TIMEDWAIT + /** + * wrapped POSIX semaphore object + */ + sem_t sem; +#else /* !HAVE_SEM_TIMEDWAIT */ + + /** + * Mutex to lock count variable + */ + mutex_t *mutex; + + /** + * Condvar to signal count increase + */ + condvar_t *cond; + + /** + * Semaphore count value + */ + u_int count; +#endif /* HAVE_SEM_TIMEDWAIT */ +}; + +METHOD(semaphore_t, wait_, void, + private_semaphore_t *this) +{ +#ifdef HAVE_SEM_TIMEDWAIT + sem_wait(&this->sem); +#else /* !HAVE_SEM_TIMEDWAIT */ + this->mutex->lock(this->mutex); + while (this->count == 0) + { + this->cond->wait(this->cond, this->mutex); + } + this->count--; + this->mutex->unlock(this->mutex); +#endif /* HAVE_SEM_TIMEDWAIT */ +} + +METHOD(semaphore_t, timed_wait_abs, bool, + private_semaphore_t *this, timeval_t tv) +{ +#ifdef HAVE_SEM_TIMEDWAIT + timespec_t ts; + + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + + /* there are errors other than ETIMEDOUT possible, but we consider them + * all as timeout */ + return sem_timedwait(&this->sem, &ts) == -1; +#else /* !HAVE_SEM_TIMEDWAIT */ + this->mutex->lock(this->mutex); + while (this->count == 0) + { + if (this->cond->timed_wait_abs(this->cond, this->mutex, tv)) + { + this->mutex->unlock(this->mutex); + return TRUE; + } + } + this->count--; + this->mutex->unlock(this->mutex); + return FALSE; +#endif /* HAVE_SEM_TIMEDWAIT */ +} + +METHOD(semaphore_t, timed_wait, bool, + private_semaphore_t *this, u_int timeout) +{ + timeval_t tv, add; + + add.tv_sec = timeout / 1000; + add.tv_usec = (timeout % 1000) * 1000; + + time_monotonic(&tv); + timeradd(&tv, &add, &tv); + + return timed_wait_abs(this, tv); +} + +METHOD(semaphore_t, post, void, + private_semaphore_t *this) +{ +#ifdef HAVE_SEM_TIMEDWAIT + sem_post(&this->sem); +#else /* !HAVE_SEM_TIMEDWAIT */ + this->mutex->lock(this->mutex); + this->count++; + this->mutex->unlock(this->mutex); + this->cond->signal(this->cond); +#endif /* HAVE_SEM_TIMEDWAIT */ +} + +METHOD(semaphore_t, destroy, void, + private_semaphore_t *this) +{ +#ifdef HAVE_SEM_TIMEDWAIT + sem_destroy(&this->sem); +#else /* !HAVE_SEM_TIMEDWAIT */ + this->cond->destroy(this->cond); + this->mutex->destroy(this->mutex); +#endif /* HAVE_SEM_TIMEDWAIT */ + free(this); +} + +/* + * Described in header + */ +semaphore_t *semaphore_create(u_int value) +{ + private_semaphore_t *this; + + INIT(this, + .public = { + .wait = _wait_, + .timed_wait = _timed_wait, + .timed_wait_abs = _timed_wait_abs, + .post = _post, + .destroy = _destroy, + }, + ); + +#ifdef HAVE_SEM_TIMEDWAIT + sem_init(&this->sem, 0, value); +#else /* !HAVE_SEM_TIMEDWAIT */ + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->cond = condvar_create(CONDVAR_TYPE_DEFAULT); + this->count = value; +#endif /* HAVE_SEM_TIMEDWAIT */ + + return &this->public; +} + diff --git a/src/libstrongswan/threading/semaphore.h b/src/libstrongswan/threading/semaphore.h new file mode 100644 index 000000000..cdb0a6f19 --- /dev/null +++ b/src/libstrongswan/threading/semaphore.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup semaphore semaphore + * @{ @ingroup threading + */ + +#ifndef THREADING_SEMAPHORE_H_ +#define THREADING_SEMAPHORE_H_ + +typedef struct semaphore_t semaphore_t; + +/** + * A semaphore is basically an integer whose value is never allowed to be + * lower than 0. Two operations can be performed on it: increment the + * value by one, and decrement the value by one. If the value is currently + * zero, then the decrement operation will blcok until the value becomes + * greater than zero. + */ +struct semaphore_t { + + /** + * Decrease the value by one, if it is greater than zero. Otherwise the + * current thread is blocked and it waits until the value increases. + */ + void (*wait)(semaphore_t *this); + + /** + * Decrease the value by one, if it is greater than zero. Otherwise the + * current thread is blocked and it waits until the value increases, or the + * call times out. + * + * @param timeout timeout im ms + * @return TRUE if timed out, FALSE otherwise + */ + bool (*timed_wait)(semaphore_t *this, u_int timeout); + + /** + * Decrease the value by one, if it is greater than zero. Otherwise the + * current thread is blocked and it waits until the value increases, or the + * call times out. + * + * The passed timeval should be calculated based on the time_monotonic() + * function. + * + * @param tv absolute time until timeout + * @return TRUE if timed out, FALSE otherwise + */ + bool (*timed_wait_abs)(semaphore_t *this, timeval_t tv); + + /** + * Increase the value by one. If the value becomes greater than zero, then + * another thread waiting will be woken up. + */ + void (*post)(semaphore_t *this); + + /** + * Destroy a semaphore and free its resources. + */ + void (*destroy)(semaphore_t *this); +}; + +/** + * Create a semaphore instance. + * + * @param value initial value (typically 0) + * @return semaphore instance + */ +semaphore_t *semaphore_create(u_int value); + +#endif /** THREADING_SEMAPHORE_H_ @} */ + diff --git a/src/libstrongswan/threading/spinlock.c b/src/libstrongswan/threading/spinlock.c new file mode 100644 index 000000000..812cf696b --- /dev/null +++ b/src/libstrongswan/threading/spinlock.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include /* for _POSIX_SPIN_LOCKS */ +#include + +#include +#include + +#include "spinlock.h" +#include "mutex.h" +#include "lock_profiler.h" + +#if defined(_POSIX_SPIN_LOCKS) && _POSIX_SPIN_LOCKS == -1 +#undef _POSIX_SPIN_LOCKS +#endif + +typedef struct private_spinlock_t private_spinlock_t; + +/** + * private data + */ +struct private_spinlock_t { + + /** + * public functions + */ + spinlock_t public; + +#ifdef _POSIX_SPIN_LOCKS + + /** + * wrapped pthread spin lock + */ + pthread_spinlock_t spinlock; + + /** + * profiling info, if enabled (the mutex below does profile itself) + */ + lock_profile_t profile; + +#else /* _POSIX_SPIN_LOCKS */ + + /** + * use a mutex if spin locks are not available + */ + mutex_t *mutex; + +#endif /* _POSIX_SPIN_LOCKS */ +}; + +METHOD(spinlock_t, lock, void, + private_spinlock_t *this) +{ +#ifdef _POSIX_SPIN_LOCKS + int err; + + profiler_start(&this->profile); + err = pthread_spin_lock(&this->spinlock); + if (err) + { + DBG1(DBG_LIB, "!!! SPIN LOCK LOCK ERROR: %s !!!", strerror(err)); + } + profiler_end(&this->profile); +#else + this->mutex->lock(this->mutex); +#endif +} + +METHOD(spinlock_t, unlock, void, + private_spinlock_t *this) +{ +#ifdef _POSIX_SPIN_LOCKS + int err; + + err = pthread_spin_unlock(&this->spinlock); + if (err) + { + DBG1(DBG_LIB, "!!! SPIN LOCK UNLOCK ERROR: %s !!!", strerror(err)); + } +#else + this->mutex->unlock(this->mutex); +#endif +} + +METHOD(spinlock_t, destroy, void, + private_spinlock_t *this) +{ +#ifdef _POSIX_SPIN_LOCKS + profiler_cleanup(&this->profile); + pthread_spin_destroy(&this->spinlock); +#else + this->mutex->destroy(this->mutex); +#endif + free(this); +} + +/* + * Described in header + */ +spinlock_t *spinlock_create() +{ + private_spinlock_t *this; + + INIT(this, + .public = { + .lock = _lock, + .unlock = _unlock, + .destroy = _destroy, + }, + ); + +#ifdef _POSIX_SPIN_LOCKS + pthread_spin_init(&this->spinlock, PTHREAD_PROCESS_PRIVATE); + profiler_init(&this->profile); +#else + #warning Using mutexes as spin lock alternatives + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); +#endif + + return &this->public; +} + + diff --git a/src/libstrongswan/threading/spinlock.h b/src/libstrongswan/threading/spinlock.h new file mode 100644 index 000000000..883980cc2 --- /dev/null +++ b/src/libstrongswan/threading/spinlock.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup spinlock spinlock + * @{ @ingroup threading + */ + +#ifndef THREADING_SPINLOCK_H_ +#define THREADING_SPINLOCK_H_ + +typedef struct spinlock_t spinlock_t; + +/** + * Spin lock wrapper implements a lock with low overhead when the lock is held + * only for a short time (waiting wastes processor cycles, though). + * + * If native spin locks are not available regular mutexes are used as fallback. + */ +struct spinlock_t { + + /** + * Acquire the lock. + */ + void (*lock)(spinlock_t *this); + + /** + * Release the lock. + */ + void (*unlock)(spinlock_t *this); + + /** + * Destroy the instance. + */ + void (*destroy)(spinlock_t *this); +}; + +/** + * Create a spin lock instance. + * + * @return unlocked instance + */ +spinlock_t *spinlock_create(); + +#endif /** THREADING_SPINLOCK_H_ @} */ + diff --git a/src/libstrongswan/threading/thread.c b/src/libstrongswan/threading/thread.c index 49a1b8430..9ef514ebc 100644 --- a/src/libstrongswan/threading/thread.c +++ b/src/libstrongswan/threading/thread.c @@ -114,7 +114,7 @@ typedef struct { /** * Next thread ID. */ -static u_int next_id = 1; +static u_int next_id; /** * Mutex to safely access the next thread ID. @@ -452,6 +452,7 @@ void threads_init() dummy1 = thread_value_create(NULL); + next_id = 1; main_thread->id = 0; main_thread->thread_id = pthread_self(); current_thread = thread_value_create(NULL); @@ -482,4 +483,3 @@ void threads_deinit() current_thread->destroy(current_thread); id_mutex->destroy(id_mutex); } - diff --git a/src/libstrongswan/threading/thread_value.c b/src/libstrongswan/threading/thread_value.c index 3fa70acb2..190b7434f 100644 --- a/src/libstrongswan/threading/thread_value.c +++ b/src/libstrongswan/threading/thread_value.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -33,6 +33,11 @@ struct private_thread_value_t { */ pthread_key_t key; + /** + * Destructor to cleanup the value of the thread destroying this object + */ + thread_cleanup_t destructor; + }; METHOD(thread_value_t, set, void, @@ -50,11 +55,22 @@ METHOD(thread_value_t, get, void*, METHOD(thread_value_t, destroy, void, private_thread_value_t *this) { + void *val; + + /* the destructor is not called automatically for the thread calling + * pthread_key_delete() */ + if (this->destructor) + { + val = pthread_getspecific(this->key); + if (val) + { + this->destructor(val); + } + } pthread_key_delete(this->key); free(this); } - /** * Described in header. */ @@ -68,6 +84,7 @@ thread_value_t *thread_value_create(thread_cleanup_t destructor) .get = _get, .destroy = _destroy, }, + .destructor = destructor, ); pthread_key_create(&this->key, destructor); diff --git a/src/libstrongswan/utils.c b/src/libstrongswan/utils.c index f76245a19..d43a4bc2f 100644 --- a/src/libstrongswan/utils.c +++ b/src/libstrongswan/utils.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2005-2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -25,6 +25,7 @@ #include #include #include +#include #include "enum.h" #include "debug.h" @@ -194,6 +195,85 @@ bool mkdir_p(const char *path, mode_t mode) return TRUE; } + +/** + * The size of the thread-specific error buffer + */ +#define STRERROR_BUF_LEN 256 + +/** + * Key to store thread-specific error buffer + */ +static pthread_key_t strerror_buf_key; + +/** + * Only initialize the key above once + */ +static pthread_once_t strerror_buf_key_once = PTHREAD_ONCE_INIT; + +/** + * Create the key used for the thread-specific error buffer + */ +static void create_strerror_buf_key() +{ + pthread_key_create(&strerror_buf_key, free); +} + +/** + * Retrieve the error buffer assigned to the current thread (or create it) + */ +static inline char *get_strerror_buf() +{ + char *buf; + + pthread_once(&strerror_buf_key_once, create_strerror_buf_key); + buf = pthread_getspecific(strerror_buf_key); + if (!buf) + { + buf = malloc(STRERROR_BUF_LEN); + pthread_setspecific(strerror_buf_key, buf); + } + return buf; +} + +#ifdef HAVE_STRERROR_R +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + char *buf = get_strerror_buf(), *msg; + +#ifdef STRERROR_R_CHAR_P + /* char* version which may or may not return the original buffer */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN); +#else + /* int version returns 0 on success */ + msg = strerror_r(errnum, buf, STRERROR_BUF_LEN) ? "Unknown error" : buf; +#endif + return msg; +} +#else /* HAVE_STRERROR_R */ +/* we actually wan't to call strerror(3) below */ +#undef strerror +/* + * Described in header. + */ +const char *safe_strerror(int errnum) +{ + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *buf = get_strerror_buf(); + + /* use a mutex to ensure calling strerror(3) is thread-safe */ + pthread_mutex_lock(&mutex); + strncpy(buf, strerror(errnum), STRERROR_BUF_LEN); + pthread_mutex_unlock(&mutex); + buf[STRERROR_BUF_LEN - 1] = '\0'; + return buf; +} +#endif /* HAVE_STRERROR_R */ + + #ifndef HAVE_CLOSEFROM /** * Described in header. @@ -315,7 +395,6 @@ void nop() } #ifndef HAVE_GCC_ATOMIC_OPERATIONS -#include /** * We use a single mutex for all refcount variables. @@ -371,7 +450,7 @@ _cas_impl(ptr, void*) /** * Described in header. */ -int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { static const char* months[] = { @@ -384,7 +463,7 @@ int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (time == UNDEFINED_TIME) { - return print_in_hook(dst, len, "--- -- --:--:--%s----", + return print_in_hook(data, "--- -- --:--:--%s----", utc ? " UTC " : " "); } if (utc) @@ -395,7 +474,7 @@ int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, { localtime_r(time, &t); } - return print_in_hook(dst, len, "%s %02d %02d:%02d:%02d%s%04d", + return print_in_hook(data, "%s %02d %02d:%02d:%02d%s%04d", months[t.tm_mon], t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, utc ? " UTC " : " ", t.tm_year + 1900); } @@ -403,7 +482,7 @@ int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, /** * Described in header. */ -int time_delta_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { char* unit = "second"; @@ -426,7 +505,7 @@ int time_delta_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, delta /= 60; unit = "minute"; } - return print_in_hook(dst, len, "%" PRIu64 " %s%s", delta, unit, + return print_in_hook(data, "%" PRIu64 " %s%s", delta, unit, (delta == 1) ? "" : "s"); } @@ -440,7 +519,7 @@ static char hexdig_upper[] = "0123456789ABCDEF"; /** * Described in header. */ -int mem_printf_hook(char *dst, size_t dstlen, +int mem_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { char *bytes = *((void**)(args[0])); @@ -455,7 +534,7 @@ int mem_printf_hook(char *dst, size_t dstlen, int i = 0; int written = 0; - written += print_in_hook(dst, dstlen, "=> %u bytes @ %p", len, bytes); + written += print_in_hook(data, "=> %u bytes @ %p", len, bytes); while (bytes_pos < bytes_roof) { @@ -476,7 +555,7 @@ int mem_printf_hook(char *dst, size_t dstlen, *buffer_pos++ = '\0'; ascii_buffer[i] = '\0'; - written += print_in_hook(dst, dstlen, "\n%4d: %s %s", + written += print_in_hook(data, "\n%4d: %s %s", line_start, buffer, ascii_buffer); buffer_pos = buffer; diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index cedfe8fd1..f47c65ac1 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -52,9 +52,33 @@ #define BUF_LEN 512 /** - * Macro compares two strings for equality + * General purpose boolean type. */ -#define streq(x,y) (strcmp(x, y) == 0) +#ifdef HAVE_STDBOOL_H +# include +#else +# ifndef HAVE__BOOL +# define _Bool signed char +# endif /* HAVE__BOOL */ +# define bool _Bool +# define false 0 +# define true 1 +# define __bool_true_false_are_defined 1 +#endif /* HAVE_STDBOOL_H */ +#ifndef FALSE +# define FALSE false +#endif /* FALSE */ +#ifndef TRUE +# define TRUE true +#endif /* TRUE */ + +/** + * Helper function that compares two strings for equality + */ +static inline bool streq(const char *x, const char *y) +{ + return strcmp(x, y) == 0; +} /** * Macro compares two strings for equality, length limited @@ -62,9 +86,12 @@ #define strneq(x,y,len) (strncmp(x, y, len) == 0) /** - * Macro compares two strings for equality ignoring case + * Helper function that compares two strings for equality ignoring case */ -#define strcaseeq(x,y) (strcasecmp(x, y) == 0) +static inline bool strcaseeq(const char *x, const char *y) +{ + return strcasecmp(x, y) == 0; +} /** * Macro compares two strings for equality ignoring case, length limited @@ -74,7 +101,10 @@ /** * NULL-safe strdup variant */ -#define strdupnull(x) ({ char *_x = x; _x ? strdup(_x) : NULL; }) +static inline char *strdupnull(const char *s) +{ + return s ? strdup(s) : NULL; +} /** * Macro compares two binary blobs for equality @@ -121,9 +151,8 @@ /** * Object allocation/initialization macro, using designated initializer. */ -#define INIT(this, ...) ({ (this) = malloc(sizeof(*(this))); \ - *(this) = (typeof(*(this))){ __VA_ARGS__ }; \ - (this); }) +#define INIT(this, ...) { (this) = malloc(sizeof(*(this))); \ + *(this) = (typeof(*(this))){ __VA_ARGS__ }; } /** * Method declaration/definition macro, providing private and public interface. @@ -136,7 +165,7 @@ #define METHOD(iface, name, ret, this, ...) \ static ret name(union {iface *_public; this;} \ __attribute__((transparent_union)), ##__VA_ARGS__); \ - static const typeof(name) *_##name = (const typeof(name)*)name; \ + static typeof(name) *_##name = (typeof(name)*)name; \ static ret name(this, ##__VA_ARGS__) /** @@ -145,7 +174,7 @@ #define METHOD2(iface1, iface2, name, ret, this, ...) \ static ret name(union {iface1 *_public1; iface2 *_public2; this;} \ __attribute__((transparent_union)), ##__VA_ARGS__); \ - static const typeof(name) *_##name = (const typeof(name)*)name; \ + static typeof(name) *_##name = (typeof(name)*)name; \ static ret name(this, ##__VA_ARGS__) /** @@ -200,27 +229,6 @@ */ #define TIME_32_BIT_SIGNED_MAX 0x7fffffff -/** - * General purpose boolean type. - */ -#ifdef HAVE_STDBOOL_H -# include -#else -# ifndef HAVE__BOOL -# define _Bool signed char -# endif /* HAVE__BOOL */ -# define bool _Bool -# define false 0 -# define true 1 -# define __bool_true_false_are_defined 1 -#endif /* HAVE_STDBOOL_H */ -#ifndef FALSE -# define FALSE false -#endif /* FALSE */ -#ifndef TRUE -# define TRUE true -#endif /* TRUE */ - /** * define some missing fixed width int types on OpenSolaris. * TODO: since the uintXX_t types are defined by the C99 standard we should @@ -408,6 +416,23 @@ char *translate(char *str, const char *from, const char *to); */ bool mkdir_p(const char *path, mode_t mode); +/** + * Thread-safe wrapper around strerror and strerror_r. + * + * This is required because the first is not thread-safe (on some platforms) + * and the second uses two different signatures (POSIX/GNU) and is impractical + * to use anyway. + * + * @param errnum error code (i.e. errno) + * @return error message + */ +const char *safe_strerror(int errnum); + +/** + * Replace usages of strerror(3) with thread-safe variant. + */ +#define strerror(errnum) safe_strerror(errnum) + #ifndef HAVE_CLOSEFROM /** * Close open file descriptors greater than or equal to lowfd. @@ -491,6 +516,11 @@ static inline void htoun32(void *network, u_int32_t host) static inline void htoun64(void *network, u_int64_t host) { char *unaligned = (char*)network; + +#ifdef be64toh + host = htobe64(host); + memcpy((char*)unaligned, &host, sizeof(host)); +#else u_int32_t high_part, low_part; high_part = host >> 32; @@ -501,6 +531,7 @@ static inline void htoun64(void *network, u_int64_t host) memcpy(unaligned, &high_part, sizeof(high_part)); unaligned += sizeof(high_part); memcpy(unaligned, &low_part, sizeof(low_part)); +#endif } /** @@ -542,6 +573,13 @@ static inline u_int32_t untoh32(void *network) static inline u_int64_t untoh64(void *network) { char *unaligned = (char*)network; + +#ifdef be64toh + u_int64_t tmp; + + memcpy(&tmp, unaligned, sizeof(tmp)); + return be64toh(tmp); +#else u_int32_t high_part, low_part; memcpy(&high_part, unaligned, sizeof(high_part)); @@ -552,6 +590,7 @@ static inline u_int64_t untoh64(void *network) low_part = ntohl(low_part); return (((u_int64_t)high_part) << 32) + low_part; +#endif } /** @@ -612,7 +651,6 @@ bool cas_bool(bool *ptr, bool oldval, bool newval); */ bool cas_ptr(void **ptr, void *oldval, void *newval); - #endif /* HAVE_GCC_ATOMIC_OPERATIONS */ /** @@ -621,7 +659,7 @@ bool cas_ptr(void **ptr, void *oldval, void *newval); * Arguments are: * time_t* time, bool utc */ -int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int time_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); /** @@ -630,7 +668,7 @@ int time_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, * Arguments are: * time_t* begin, time_t* end */ -int time_delta_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int time_delta_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); /** @@ -639,7 +677,7 @@ int time_delta_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, * Arguments are: * u_char *ptr, u_int len */ -int mem_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int mem_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** UTILS_H_ @}*/ diff --git a/src/libstrongswan/utils/backtrace.c b/src/libstrongswan/utils/backtrace.c index cb83d9830..b6015fb35 100644 --- a/src/libstrongswan/utils/backtrace.c +++ b/src/libstrongswan/utils/backtrace.c @@ -50,6 +50,284 @@ struct private_backtrace_t { void *frames[]; }; +#ifdef HAVE_DLADDR +#ifdef HAVE_BFD_H + +#include +#include +#include + +/** + * Hashtable-cached bfd handle + */ +typedef struct { + /** binary file name on disk */ + char *filename; + /** bfd handle */ + bfd *abfd; + /** loaded symbols */ + asymbol **syms; +} bfd_entry_t; + +/** + * Destroy a bfd_entry + */ +static void bfd_entry_destroy(bfd_entry_t *this) +{ + free(this->filename); + free(this->syms); + bfd_close(this->abfd); + free(this); +} + +/** + * Data to pass to find_addr() + */ +typedef struct { + /** used bfd entry */ + bfd_entry_t *entry; + /** backtrace address */ + bfd_vma vma; + /** stream to log to */ + FILE *file; + /** TRUE if complete */ + bool found; +} bfd_find_data_t; + +/** + * bfd entry cache + */ +static hashtable_t *bfds; + +static mutex_t *bfd_mutex; + +/** + * Hashtable hash function + */ +static u_int bfd_hash(char *key) +{ + return chunk_hash(chunk_create(key, strlen(key))); +} + +/** + * Hashtable equals function + */ +static bool bfd_equals(char *a, char *b) +{ + return streq(a, b); +} + +/** + * See header. + */ +void backtrace_init() +{ + bfd_init(); + bfds = hashtable_create((hashtable_hash_t)bfd_hash, + (hashtable_equals_t)bfd_equals, 8); + bfd_mutex = mutex_create(MUTEX_TYPE_DEFAULT); +} + +/** + * See header. + */ +void backtrace_deinit() +{ + enumerator_t *enumerator; + bfd_entry_t *entry; + char *key; + + enumerator = bfds->create_enumerator(bfds); + while (enumerator->enumerate(enumerator, &key, &entry)) + { + bfds->remove_at(bfds, enumerator); + bfd_entry_destroy(entry); + } + enumerator->destroy(enumerator); + + bfds->destroy(bfds); + bfd_mutex->destroy(bfd_mutex); +} + +/** + * Find and print information to an address + */ +static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data) +{ + bfd_size_type size; + bfd_vma vma; + const char *source; + const char *function; + u_int line; + + if (!data->found || (bfd_get_section_flags(abfd, section) & SEC_ALLOC) != 0) + { + vma = bfd_get_section_vma(abfd, section); + if (data->vma >= vma) + { + size = bfd_get_section_size(section); + if (data->vma < vma + size) + { + data->found = bfd_find_nearest_line(abfd, section, + data->entry->syms, data->vma - vma, + &source, &function, &line); + if (data->found) + { + if (source || function) + { + fprintf(data->file, " -> "); + if (function) + { + fprintf(data->file, "\e[34m%s() ", function); + } + if (source) + { + fprintf(data->file, "\e[32m@ %s:%d", source, line); + } + fprintf(data->file, "\e[0m\n"); + } + } + } + } + } +} + +/** + * Find a cached bfd entry, create'n'cache if not found + */ +static bfd_entry_t *get_bfd_entry(char *filename) +{ + bool dynamic = FALSE, ok = FALSE; + bfd_entry_t *entry; + long size; + + /* check cache */ + entry = bfds->get(bfds, filename); + if (entry) + { + return entry; + } + + INIT(entry, + .abfd = bfd_openr(filename, NULL), + ); + + if (!entry->abfd) + { + free(entry); + return NULL; + } +#ifdef BFD_DECOMPRESS + entry->abfd->flags |= BFD_DECOMPRESS; +#endif + if (bfd_check_format(entry->abfd, bfd_archive) == 0 && + bfd_check_format_matches(entry->abfd, bfd_object, NULL)) + { + if (bfd_get_file_flags(entry->abfd) & HAS_SYMS) + { + size = bfd_get_symtab_upper_bound(entry->abfd); + if (size == 0) + { + size = bfd_get_dynamic_symtab_upper_bound(entry->abfd); + } + if (size >= 0) + { + entry->syms = malloc(size); + if (dynamic) + { + ok = bfd_canonicalize_dynamic_symtab(entry->abfd, + entry->syms) >= 0; + } + else + { + ok = bfd_canonicalize_symtab(entry->abfd, + entry->syms) >= 0; + } + } + } + } + if (ok) + { + entry->filename = strdup(filename); + bfds->put(bfds, entry->filename, entry); + return entry; + } + bfd_entry_destroy(entry); + return NULL; +} + +/** + * Print the source file with line number to file, libbfd variant + */ +static void print_sourceline(FILE *file, char *filename, void *ptr) +{ + bfd_entry_t *entry; + bfd_find_data_t data = { + .file = file, + .vma = (uintptr_t)ptr, + }; + bool old = FALSE; + + bfd_mutex->lock(bfd_mutex); + if (lib->leak_detective) + { + old = lib->leak_detective->set_state(lib->leak_detective, FALSE); + } + entry = get_bfd_entry(filename); + if (entry) + { + data.entry = entry; + bfd_map_over_sections(entry->abfd, (void*)find_addr, &data); + } + if (lib->leak_detective) + { + lib->leak_detective->set_state(lib->leak_detective, old); + } + bfd_mutex->unlock(bfd_mutex); +} + +#else /* !HAVE_BFD_H */ + +void backtrace_init() {} +void backtrace_deinit() {} + +/** + * Print the source file with line number to file, slow addr2line variant + */ +static void print_sourceline(FILE *file, char *filename, void *ptr) +{ + char cmd[1024]; + FILE *output; + int c; + + snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", filename, ptr); + output = popen(cmd, "r"); + if (output) + { + fprintf(file, " -> \e[32m"); + while (TRUE) + { + c = getc(output); + if (c == '\n' || c == EOF) + { + break; + } + fputc(c, file); + } + pclose(output); + fprintf(file, "\e[0m\n"); + } +} + +#endif /* HAVE_BFD_H */ + +#else /* !HAVE_DLADDR */ + +void backtrace_init() {} +void backtrace_deinit() {} + +#endif /* HAVE_DLADDR */ + METHOD(backtrace_t, log_, void, private_backtrace_t *this, FILE *file, bool detailed) { @@ -67,9 +345,6 @@ METHOD(backtrace_t, log_, void, if (dladdr(this->frames[i], &info)) { - char cmd[1024]; - FILE *output; - int c; void *ptr = this->frames[i]; if (strstr(info.dli_fname, ".so")) @@ -89,37 +364,14 @@ METHOD(backtrace_t, log_, void, } if (detailed) { - fprintf(file, " -> \e[32m"); - snprintf(cmd, sizeof(cmd), "addr2line -e %s %p", - info.dli_fname, ptr); - output = popen(cmd, "r"); - if (output) - { - while (TRUE) - { - c = getc(output); - if (c == '\n' || c == EOF) - { - break; - } - fputc(c, file); - } - pclose(output); - } - else - { - #endif /* HAVE_DLADDR */ - fprintf(file, " %s\n", strings[i]); - #ifdef HAVE_DLADDR - } - fprintf(file, "\n\e[0m"); + print_sourceline(file, (char*)info.dli_fname, ptr); } } else +#endif /* HAVE_DLADDR */ { fprintf(file, " %s\n", strings[i]); } -#endif /* HAVE_DLADDR */ } free (strings); #else /* !HAVE_BACKTRACE */ @@ -248,3 +500,20 @@ backtrace_t *backtrace_create(int skip) return &this->public; } +/** + * See header + */ +void backtrace_dump(char *label, FILE *file, bool detailed) +{ + backtrace_t *backtrace; + + backtrace = backtrace_create(2); + + if (label) + { + fprintf(file, "Debug backtrace: %s\n", label); + } + backtrace->log(backtrace, file, detailed); + backtrace->destroy(backtrace); +} + diff --git a/src/libstrongswan/utils/backtrace.h b/src/libstrongswan/utils/backtrace.h index 9d59d2503..aeeba4dd6 100644 --- a/src/libstrongswan/utils/backtrace.h +++ b/src/libstrongswan/utils/backtrace.h @@ -77,4 +77,23 @@ struct backtrace_t { */ backtrace_t *backtrace_create(int skip); +/** + * Create a backtrace, dump it and clean it up. + * + * @param label description to print for this backtrace, or NULL + * @param file FILE to log backtrace to + * @param detailed TRUE to resolve line/file using addr2line (slow) + */ +void backtrace_dump(char *label, FILE *file, bool detailed); + +/** + * Initialize backtracing framework. + */ +void backtrace_init(); + +/** + * Deinitialize backtracing framework. + */ +void backtrace_deinit(); + #endif /** BACKTRACE_H_ @}*/ diff --git a/src/libstrongswan/utils/blocking_queue.c b/src/libstrongswan/utils/blocking_queue.c new file mode 100644 index 000000000..c70184198 --- /dev/null +++ b/src/libstrongswan/utils/blocking_queue.c @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "blocking_queue.h" + +#include +#include +#include +#include + +typedef struct private_blocking_queue_t private_blocking_queue_t; + +/** + * Private data of a blocking_queue_t object. + */ +struct private_blocking_queue_t { + + /** + * Public part + */ + blocking_queue_t public; + + /** + * Linked list containing all items in the queue + */ + linked_list_t *list; + + /** + * Mutex used to synchronize access to the queue + */ + mutex_t *mutex; + + /** + * Condvar used to wait for items + */ + condvar_t *condvar; + +}; + +METHOD(blocking_queue_t, enqueue, void, + private_blocking_queue_t *this, void *item) +{ + this->mutex->lock(this->mutex); + this->list->insert_first(this->list, item); + this->condvar->signal(this->condvar); + this->mutex->unlock(this->mutex); +} + +METHOD(blocking_queue_t, dequeue, void*, + private_blocking_queue_t *this) +{ + bool oldstate; + void *item; + + + this->mutex->lock(this->mutex); + thread_cleanup_push((thread_cleanup_t)this->mutex->unlock, this->mutex); + /* ensure that a canceled thread does not dequeue any items */ + thread_cancellation_point(); + while (this->list->remove_last(this->list, &item) != SUCCESS) + { + oldstate = thread_cancelability(TRUE); + this->condvar->wait(this->condvar, this->mutex); + thread_cancelability(oldstate); + } + thread_cleanup_pop(TRUE); + return item; +} + +METHOD(blocking_queue_t, destroy, void, + private_blocking_queue_t *this) +{ + this->list->destroy(this->list); + this->condvar->destroy(this->condvar); + this->mutex->destroy(this->mutex); + free(this); +} + +METHOD(blocking_queue_t, destroy_offset, void, + private_blocking_queue_t *this, size_t offset) +{ + this->list->invoke_offset(this->list, offset); + destroy(this); +} + +METHOD(blocking_queue_t, destroy_function, void, + private_blocking_queue_t *this, void (*fn)(void*)) +{ + this->list->invoke_function(this->list, (linked_list_invoke_t)fn); + destroy(this); +} + +/* + * Described in header. + */ +blocking_queue_t *blocking_queue_create() +{ + private_blocking_queue_t *this; + + INIT(this, + .public = { + .enqueue = _enqueue, + .dequeue = _dequeue, + .destroy = _destroy, + .destroy_offset = _destroy_offset, + .destroy_function = _destroy_function, + }, + .list = linked_list_create(), + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), + .condvar = condvar_create(CONDVAR_TYPE_DEFAULT), + ); + + return &this->public; +} + diff --git a/src/libstrongswan/utils/blocking_queue.h b/src/libstrongswan/utils/blocking_queue.h new file mode 100644 index 000000000..cf2712cf4 --- /dev/null +++ b/src/libstrongswan/utils/blocking_queue.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup blocking_queue blocking_queue + * @{ @ingroup utils + */ + +#ifndef BLOCKING_QUEUE_H_ +#define BLOCKING_QUEUE_H_ + +typedef struct blocking_queue_t blocking_queue_t; + +#include + +/** + * Class implementing a synchronized blocking queue based on linked_list_t + */ +struct blocking_queue_t { + + /** + * Inserts a new item at the tail of the queue + * + * @param item item to insert in queue + */ + void (*enqueue)(blocking_queue_t *this, void *item); + + /** + * Removes the first item in the queue and returns its value. + * If the queue is empty, this call blocks until a new item is inserted. + * + * @note This is a thread cancellation point + * + * @return removed item + */ + void *(*dequeue)(blocking_queue_t *this); + + /** + * Destroys a blocking_queue_t object. + * + * @note No thread must wait in dequeue() when this function is called + */ + void (*destroy)(blocking_queue_t *this); + + /** + * Destroys a queue and its objects using the given destructor. + * + * If a queue and the contained objects should be destroyed, use + * destroy_offset. The supplied offset specifies the destructor to + * call on each object. The offset may be calculated using the offsetof + * macro, e.g.: queue->destroy_offset(queue, offsetof(object_t, destroy)); + * + * @note No thread must wait in dequeue() when this function is called + * + * @param offset offset of the objects destructor + */ + void (*destroy_offset)(blocking_queue_t *this, size_t offset); + + /** + * Destroys a queue and its objects using a cleanup function. + * + * If a queue and its contents should get destroyed using a specific + * cleanup function, use destroy_function. This is useful when the + * list contains malloc()-ed blocks which should get freed, + * e.g.: queue->destroy_function(queue, free); + * + * @note No thread must wait in dequeue() when this function is called + * + * @param function function to call on each object + */ + void (*destroy_function)(blocking_queue_t *this, void (*)(void*)); + +}; + +/** + * Creates an empty queue object. + * + * @return blocking_queue_t object. + */ +blocking_queue_t *blocking_queue_create(); + +#endif /** BLOCKING_QUEUE_H_ @}*/ + diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c new file mode 100644 index 000000000..34128d010 --- /dev/null +++ b/src/libstrongswan/utils/capabilities.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "capabilities.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_PRCTL +# include +#endif /* HAVE_PRCTL */ + +#include + +#if !defined(HAVE_GETPWNAM_R) || !defined(HAVE_GETGRNAM_R) +# include +# define EMULATE_R_FUNCS +#endif + +typedef struct private_capabilities_t private_capabilities_t; + +/** + * Private data of an capabilities_t object. + */ +struct private_capabilities_t { + + /** + * Public capabilities_t interface. + */ + capabilities_t public; + + /** + * user ID to switch during rights dropping + */ + uid_t uid; + + /** + * group ID to switch during rights dropping + */ + gid_t gid; + + /** + * capabilities to keep + */ +#ifdef CAPABILITIES_LIBCAP + cap_t caps; +#endif /* CAPABILITIES_LIBCAP */ +#ifdef CAPABILITIES_NATIVE + struct __user_cap_data_struct caps[2]; +#endif /* CAPABILITIES_NATIVE */ + +#ifdef EMULATE_R_FUNCS + /** + * mutex to emulate get(pw|gr)nam_r functions + */ + mutex_t *mutex; +#endif +}; + +METHOD(capabilities_t, keep, void, + private_capabilities_t *this, u_int cap) +{ +#ifdef CAPABILITIES_LIBCAP + cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); + cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET); + cap_set_flag(this->caps, CAP_PERMITTED, 1, &cap, CAP_SET); +#endif /* CAPABILITIES_LIBCAP */ +#ifdef CAPABILITIES_NATIVE + int i = 0; + + if (cap >= 32) + { + i++; + cap -= 32; + } + this->caps[i].effective |= 1 << cap; + this->caps[i].permitted |= 1 << cap; + this->caps[i].inheritable |= 1 << cap; +#endif /* CAPABILITIES_NATIVE */ +} + +METHOD(capabilities_t, get_uid, uid_t, + private_capabilities_t *this) +{ + return this->uid; +} + +METHOD(capabilities_t, get_gid, gid_t, + private_capabilities_t *this) +{ + return this->gid; +} + +METHOD(capabilities_t, set_uid, void, + private_capabilities_t *this, uid_t uid) +{ + this->uid = uid; +} + +METHOD(capabilities_t, set_gid, void, + private_capabilities_t *this, gid_t gid) +{ + this->gid = gid; +} + +METHOD(capabilities_t, resolve_uid, bool, + private_capabilities_t *this, char *username) +{ + struct passwd *pwp; + int err; + +#ifdef HAVE_GETPWNAM_R + struct passwd passwd; + char buf[1024]; + + err = getpwnam_r(username, &passwd, buf, sizeof(buf), &pwp); + if (pwp) + { + this->uid = pwp->pw_uid; + } +#else /* HAVE GETPWNAM_R */ + this->mutex->lock(this->mutex); + pwp = getpwnam(username); + if (pwp) + { + this->uid = pwp->pw_uid; + } + err = errno; + this->mutex->unlock(this->mutex); +#endif /* HAVE GETPWNAM_R */ + if (pwp) + { + return TRUE; + } + DBG1(DBG_LIB, "resolving user '%s' failed: %s", username, + err ? strerror(err) : "user not found"); + return FALSE; +} + +METHOD(capabilities_t, resolve_gid, bool, + private_capabilities_t *this, char *groupname) +{ + struct group *grp; + int err; + +#ifdef HAVE_GETGRNAM_R + struct group group; + char buf[1024]; + + err = getgrnam_r(groupname, &group, buf, sizeof(buf), &grp); + if (grp) + { + this->gid = grp->gr_gid; + } +#else /* HAVE_GETGRNAM_R */ + this->mutex->lock(this->mutex); + grp = getgrnam(groupname); + if (grp) + { + this->gid = grp->gr_gid; + } + err = errno; + this->mutex->unlock(this->mutex); +#endif /* HAVE_GETGRNAM_R */ + if (grp) + { + return TRUE; + } + DBG1(DBG_LIB, "resolving user '%s' failed: %s", groupname, + err ? strerror(err) : "group not found"); + return FALSE; +} + +METHOD(capabilities_t, drop, bool, + private_capabilities_t *this) +{ +#ifdef HAVE_PRCTL + prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); +#endif + + if (this->gid && setgid(this->gid) != 0) + { + DBG1(DBG_LIB, "change to unprivileged group %u failed: %s", + this->gid, strerror(errno)); + return FALSE; + } + if (this->uid && setuid(this->uid) != 0) + { + DBG1(DBG_LIB, "change to unprivileged user %u failed: %s", + this->uid, strerror(errno)); + return FALSE; + } + +#ifdef CAPABILITIES_LIBCAP + if (cap_set_proc(this->caps) != 0) + { + DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno)); + return FALSE; + } +#endif /* CAPABILITIES_LIBCAP */ +#ifdef CAPABILITIES_NATIVE + struct __user_cap_header_struct header = { +#if defined(_LINUX_CAPABILITY_VERSION_3) + .version = _LINUX_CAPABILITY_VERSION_3, +#elif defined(_LINUX_CAPABILITY_VERSION_2) + .version = _LINUX_CAPABILITY_VERSION_2, +#elif defined(_LINUX_CAPABILITY_VERSION_1) + .version = _LINUX_CAPABILITY_VERSION_1, +#else + .version = _LINUX_CAPABILITY_VERSION, +#endif + }; + if (capset(&header, this->caps) != 0) + { + DBG1(DBG_LIB, "dropping capabilities failed: %s", strerror(errno)); + return FALSE; + } +#endif /* CAPABILITIES_NATIVE */ +#ifdef CAPABILITIES + DBG1(DBG_LIB, "dropped capabilities, running as uid %u, gid %u", + this->uid, this->gid); +#endif /* CAPABILITIES */ + return TRUE; +} + +METHOD(capabilities_t, destroy, void, + private_capabilities_t *this) +{ +#ifdef EMULATE_R_FUNCS + this->mutex->destroy(this->mutex); +#endif /* EMULATE_R_FUNCS */ +#ifdef CAPABILITIES_LIBCAP + cap_free(this->caps); +#endif /* CAPABILITIES_LIBCAP */ + free(this); +} + +/** + * See header + */ +capabilities_t *capabilities_create() +{ + private_capabilities_t *this; + + INIT(this, + .public = { + .keep = _keep, + .get_uid = _get_uid, + .get_gid = _get_gid, + .set_uid = _set_uid, + .set_gid = _set_gid, + .resolve_uid = _resolve_uid, + .resolve_gid = _resolve_gid, + .drop = _drop, + .destroy = _destroy, + }, + ); + +#ifdef CAPABILITIES +#ifdef CAPABILITIES_LIBCAP + this->caps = cap_init(); +#endif /* CAPABILITIES_LIBCAP */ + if (lib->leak_detective) + { + keep(this, CAP_SYS_NICE); + } +#endif /* CAPABILITIES */ + +#ifdef EMULATE_R_FUNCS + this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); +#endif /* EMULATE_R_FUNCS */ + + return &this->public; +} diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h new file mode 100644 index 000000000..cd23cbf10 --- /dev/null +++ b/src/libstrongswan/utils/capabilities.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup capabilities capabilities + * @{ @ingroup utils + */ + +#ifndef CAPABILITIES_H_ +#define CAPABILITIES_H_ + +#include +#ifdef HAVE_SYS_CAPABILITY_H +# include +#elif defined(CAPABILITIES_NATIVE) +# include +#endif + +typedef struct capabilities_t capabilities_t; + +/** + * POSIX capability dropping abstraction layer. + */ +struct capabilities_t { + + /** + * Register a capability to keep while calling drop(). + * + * @param cap capability to keep + */ + void (*keep)(capabilities_t *this, u_int cap); + + /** + * Get the user ID set through set_uid/resolve_uid. + * + * @return currently set user ID + */ + uid_t (*get_uid)(capabilities_t *this); + + /** + * Get the group ID set through set_gid/resolve_gid. + * + * @return currently set group ID + */ + gid_t (*get_gid)(capabilities_t *this); + + /** + * Set the numerical user ID to use during rights dropping. + * + * @param uid user ID to use + */ + void (*set_uid)(capabilities_t *this, uid_t uid); + + /** + * Set the numerical group ID to use during rights dropping. + * + * @param gid group ID to use + */ + void (*set_gid)(capabilities_t *this, gid_t gid); + + /** + * Resolve a username and set the user ID accordingly. + * + * @param username username get the uid for + * @return TRUE if username resolved and uid set + */ + bool (*resolve_uid)(capabilities_t *this, char *username); + + /** + * Resolve a groupname and set the group ID accordingly. + * + * @param groupname groupname to get the gid for + * @return TRUE if groupname resolved and gid set + */ + bool (*resolve_gid)(capabilities_t *this, char *groupname); + + /** + * Drop all capabilities not previously passed to keep(), switch to UID/GID. + * + * @return TRUE if capability drop successful + */ + bool (*drop)(capabilities_t *this); + + /** + * Destroy a capabilities_t. + */ + void (*destroy)(capabilities_t *this); +}; + +/** + * Create a capabilities instance. + */ +capabilities_t *capabilities_create(); + +#endif /** CAPABILITIES_H_ @}*/ diff --git a/src/libstrongswan/utils/enumerator.c b/src/libstrongswan/utils/enumerator.c index fb461b448..53c94f9dd 100644 --- a/src/libstrongswan/utils/enumerator.c +++ b/src/libstrongswan/utils/enumerator.c @@ -121,7 +121,7 @@ static bool enumerate_dir_enum(dir_enum_t *this, char **relative, /** * See header */ -enumerator_t* enumerator_create_directory(char *path) +enumerator_t* enumerator_create_directory(const char *path) { int len; dir_enum_t *this = malloc_thing(dir_enum_t); @@ -168,9 +168,9 @@ typedef struct { /** current position */ char *pos; /** separater chars */ - char *sep; + const char *sep; /** trim chars */ - char *trim; + const char *trim; } token_enum_t; /** @@ -187,7 +187,8 @@ static void destroy_token_enum(token_enum_t *this) */ static bool enumerate_token_enum(token_enum_t *this, char **token) { - char *pos = NULL, *tmp, *sep, *trim; + const char *sep, *trim; + char *pos = NULL, *tmp; bool last = FALSE; /* trim leading characters/separators */ @@ -303,7 +304,8 @@ static bool enumerate_token_enum(token_enum_t *this, char **token) /** * See header */ -enumerator_t* enumerator_create_token(char *string, char *sep, char *trim) +enumerator_t* enumerator_create_token(const char *string, const char *sep, + const char *trim) { token_enum_t *enumerator = malloc_thing(token_enum_t); diff --git a/src/libstrongswan/utils/enumerator.h b/src/libstrongswan/utils/enumerator.h index 12b5712ae..8c3d70173 100644 --- a/src/libstrongswan/utils/enumerator.h +++ b/src/libstrongswan/utils/enumerator.h @@ -93,7 +93,7 @@ enumerator_t *enumerator_create_single(void *item, void (*cleanup)(void *item)); * @param path path of the directory * @return the directory enumerator, NULL on failure */ -enumerator_t* enumerator_create_directory(char *path); +enumerator_t* enumerator_create_directory(const char *path); /** * Create an enumerator over tokens of a string. @@ -106,7 +106,8 @@ enumerator_t* enumerator_create_directory(char *path); * @param trim characters to trim from tokens * @return enumerator over char* tokens */ -enumerator_t* enumerator_create_token(char *string, char *sep, char *trim); +enumerator_t* enumerator_create_token(const char *string, const char *sep, + const char *trim); /** * Creates an enumerator which enumerates over enumerated enumerators :-). diff --git a/src/libstrongswan/utils/hashtable.c b/src/libstrongswan/utils/hashtable.c index 33f645170..d181d8ec8 100644 --- a/src/libstrongswan/utils/hashtable.c +++ b/src/libstrongswan/utils/hashtable.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -251,16 +251,21 @@ METHOD(hashtable_t, put, void*, return old_value; } -METHOD(hashtable_t, get, void*, - private_hashtable_t *this, void *key) +static void *get_internal(private_hashtable_t *this, void *key, + hashtable_equals_t equals) { void *value = NULL; pair_t *pair; + if (!this->count) + { /* no need to calculate the hash */ + return NULL; + } + pair = this->table[this->hash(key) & this->mask]; while (pair) { - if (this->equals(key, pair->key)) + if (equals(key, pair->key)) { value = pair->value; break; @@ -270,6 +275,18 @@ METHOD(hashtable_t, get, void*, return value; } +METHOD(hashtable_t, get, void*, + private_hashtable_t *this, void *key) +{ + return get_internal(this, key, this->equals); +} + +METHOD(hashtable_t, get_match, void*, + private_hashtable_t *this, void *key, hashtable_equals_t match) +{ + return get_internal(this, key, match); +} + METHOD(hashtable_t, remove_, void*, private_hashtable_t *this, void *key) { @@ -409,6 +426,7 @@ hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals, .public = { .put = _put, .get = _get, + .get_match = _get_match, .remove = _remove_, .remove_at = (void*)_remove_at, .get_count = _get_count, diff --git a/src/libstrongswan/utils/hashtable.h b/src/libstrongswan/utils/hashtable.h index 27aca9b68..0a21ca373 100644 --- a/src/libstrongswan/utils/hashtable.h +++ b/src/libstrongswan/utils/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2010 Tobias Brunner + * Copyright (C) 2008-2012 Tobias Brunner * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -77,6 +77,22 @@ struct hashtable_t { */ void *(*get) (hashtable_t *this, void *key); + /** + * Returns the value with a matching key, if the hash table contains such an + * entry, otherwise NULL is returned. + * + * Compared to get() the given match function is used to compare the keys + * for equality. The hash function does have to be deviced properly in + * order to make this work if the match function compares keys differently + * than the equals function provided to the constructor. This basically + * allows to enumerate all entries with the same hash value. + * + * @param key the key to match against + * @param match match function to be used when comparing keys + * @return the value, NULL if not found + */ + void *(*get_match) (hashtable_t *this, void *key, hashtable_equals_t match); + /** * Removes the value with the given key from the hash table and returns the * removed value (or NULL if no such value existed). diff --git a/src/libstrongswan/utils/host.c b/src/libstrongswan/utils/host.c index d3020a5d0..e17b6ad02 100644 --- a/src/libstrongswan/utils/host.c +++ b/src/libstrongswan/utils/host.c @@ -74,20 +74,16 @@ METHOD(host_t, get_sockaddr_len, socklen_t*, METHOD(host_t, is_anyaddr, bool, private_host_t *this) { + static const u_int8_t zeroes[IPV6_LEN]; + switch (this->address.sa_family) { case AF_INET: { - u_int8_t zeroes[IPV4_LEN]; - - memset(zeroes, 0, IPV4_LEN); return memeq(zeroes, &(this->address4.sin_addr.s_addr), IPV4_LEN); } case AF_INET6: { - u_int8_t zeroes[IPV6_LEN]; - - memset(zeroes, 0, IPV6_LEN); return memeq(zeroes, &(this->address6.sin6_addr.s6_addr), IPV6_LEN); } default: @@ -100,7 +96,7 @@ METHOD(host_t, is_anyaddr, bool, /** * Described in header. */ -int host_printf_hook(char *dst, size_t dstlen, printf_hook_spec_t *spec, +int host_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args) { private_host_t *this = *((private_host_t**)(args[0])); @@ -110,7 +106,7 @@ int host_printf_hook(char *dst, size_t dstlen, printf_hook_spec_t *spec, { snprintf(buffer, sizeof(buffer), "(null)"); } - else if (is_anyaddr(this)) + else if (is_anyaddr(this) && !spec->plus) { snprintf(buffer, sizeof(buffer), "%%any%s", this->address.sa_family == AF_INET6 ? "6" : ""); @@ -152,9 +148,9 @@ int host_printf_hook(char *dst, size_t dstlen, printf_hook_spec_t *spec, } if (spec->minus) { - return print_in_hook(dst, dstlen, "%-*s", spec->width, buffer); + return print_in_hook(data, "%-*s", spec->width, buffer); } - return print_in_hook(dst, dstlen, "%*s", spec->width, buffer); + return print_in_hook(data, "%*s", spec->width, buffer); } METHOD(host_t, get_address, chunk_t, @@ -430,13 +426,15 @@ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr) { case AF_INET: { - memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in)); + memcpy(&this->address4, (struct sockaddr_in*)sockaddr, + sizeof(struct sockaddr_in)); this->socklen = sizeof(struct sockaddr_in); return &this->public; } case AF_INET6: { - memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6)); + memcpy(&this->address6, (struct sockaddr_in6*)sockaddr, + sizeof(struct sockaddr_in6)); this->socklen = sizeof(struct sockaddr_in6); return &this->public; } diff --git a/src/libstrongswan/utils/host.h b/src/libstrongswan/utils/host.h index 0a1be6e47..a8b010544 100644 --- a/src/libstrongswan/utils/host.h +++ b/src/libstrongswan/utils/host.h @@ -155,7 +155,7 @@ struct host_t { * * @param string string of an address, such as "152.96.193.130" * @param port port number - * @return host_t, NULL if string not an address. + * @return host_t, NULL if string not an address. */ host_t *host_create_from_string(char *string, u_int16_t port); @@ -165,7 +165,7 @@ host_t *host_create_from_string(char *string, u_int16_t port); * @param string hostname to resolve * @param family family to prefer, 0 for first match * @param port port number - * @return host_t, NULL lookup failed + * @return host_t, NULL lookup failed */ host_t *host_create_from_dns(char *string, int family, u_int16_t port); @@ -174,10 +174,10 @@ host_t *host_create_from_dns(char *string, int family, u_int16_t port); * * If family is AF_UNSPEC, it is guessed using address.len. * - * @param family Address family, such as AF_INET or AF_INET6 + * @param family Address family, such as AF_INET or AF_INET6 * @param address address as chunk_t in network order * @param port port number - * @return host_t, NULL if family not supported/chunk invalid + * @return host_t, NULL if family not supported/chunk invalid */ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); @@ -185,7 +185,7 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port); * Constructor to create a host_t object from a sockaddr struct * * @param sockaddr sockaddr struct which contains family, address and port - * @return host_t, NULL if family not supported + * @return host_t, NULL if family not supported */ host_t *host_create_from_sockaddr(sockaddr_t *sockaddr); @@ -202,7 +202,7 @@ host_t *host_create_from_subnet(char *string, int *bits); * Create a host without an address, a "any" host. * * @param family family of the any host - * @return host_t, NULL if family not supported + * @return host_t, NULL if family not supported */ host_t *host_create_any(int family); @@ -212,8 +212,9 @@ host_t *host_create_any(int family); * Arguments are: * host_t *host * Use #-modifier to include port number + * Use +-modifier to force numeric representation (instead of e.g. %any) */ -int host_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, +int host_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec, const void *const *args); #endif /** HOST_H_ @}*/ diff --git a/src/libstrongswan/utils/identification.c b/src/libstrongswan/utils/identification.c index 9f0007f78..2669c2da6 100644 --- a/src/libstrongswan/utils/identification.c +++ b/src/libstrongswan/utils/identification.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Tobias Brunner + * Copyright (C) 2009-2012 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -310,7 +310,7 @@ static void dntoa(chunk_t dn, char *buf, size_t len) len -= written; chunk_printable(data, &printable, '?'); - written = snprintf(buf, len, "%.*s", printable.len, printable.ptr); + written = snprintf(buf, len, "%.*s", (int)printable.len, printable.ptr); chunk_free(&printable); if (written < 0 || written >= len) { @@ -414,14 +414,22 @@ static status_t atodn(char *src, chunk_t *dn) } break; case SEARCH_NAME: - if (*src != ' ' && *src != '=') + if (*src == ' ' || *src == '=') + { + break; + } + else if (*src != ',' && *src != '/') { name.ptr = src; name.len = 1; whitespace = 0; state = READ_NAME; + break; } - break; + name = chunk_empty; + whitespace = 0; + state = READ_NAME; + /* fall-through */ case READ_NAME: if (*src != ',' && *src != '/' && *src != '\0') { @@ -748,8 +756,8 @@ METHOD(identification_t, matches_dn, id_match_t, /** * Described in header. */ -int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, - const void *const *args) +int identification_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args) { private_identification_t *this = *((private_identification_t**)(args[0])); chunk_t proper; @@ -757,7 +765,7 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (this == NULL) { - return print_in_hook(dst, len, "%*s", spec->width, "(null)"); + return print_in_hook(data, "%*s", spec->width, "(null)"); } switch (this->type) @@ -783,7 +791,7 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, case ID_RFC822_ADDR: case ID_DER_ASN1_GN_URI: chunk_printable(this->encoded, &proper, '?'); - snprintf(buf, sizeof(buf), "%.*s", proper.len, proper.ptr); + snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr); chunk_free(&proper); break; case ID_DER_ASN1_DN: @@ -796,8 +804,8 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, if (chunk_printable(this->encoded, NULL, '?') && this->encoded.len != HASH_SIZE_SHA1) { /* fully printable, use ascii version */ - snprintf(buf, sizeof(buf), "%.*s", - this->encoded.len, this->encoded.ptr); + snprintf(buf, sizeof(buf), "%.*s", (int)this->encoded.len, + this->encoded.ptr); } else { /* not printable, hex dump */ @@ -813,9 +821,9 @@ int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, } if (spec->minus) { - return print_in_hook(dst, len, "%-*s", spec->width, buf); + return print_in_hook(data, "%-*s", spec->width, buf); } - return print_in_hook(dst, len, "%*s", spec->width, buf); + return print_in_hook(data, "%*s", spec->width, buf); } METHOD(identification_t, clone_, identification_t*, @@ -1016,7 +1024,7 @@ identification_t * identification_create_from_data(chunk_t data) char buf[data.len + 1]; /* use string constructor */ - snprintf(buf, sizeof(buf), "%.*s", data.len, data.ptr); + snprintf(buf, sizeof(buf), "%.*s", (int)data.len, data.ptr); return identification_create_from_string(buf); } diff --git a/src/libstrongswan/utils/identification.h b/src/libstrongswan/utils/identification.h index 3978b23f3..024fcea4b 100644 --- a/src/libstrongswan/utils/identification.h +++ b/src/libstrongswan/utils/identification.h @@ -342,7 +342,7 @@ identification_t * identification_create_from_sockaddr(sockaddr_t *sockaddr); * Arguments are: * identification_t *identification */ -int identification_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, - const void *const *args); +int identification_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args); #endif /** IDENTIFICATION_H_ @}*/ diff --git a/src/libstrongswan/utils/leak_detective.c b/src/libstrongswan/utils/leak_detective.c index 0a8789335..cface0538 100644 --- a/src/libstrongswan/utils/leak_detective.c +++ b/src/libstrongswan/utils/leak_detective.c @@ -188,6 +188,7 @@ static void uninstall_hooks() char *whitelist[] = { /* backtraces, including own */ "backtrace_create", + "safe_strerror", /* pthread stuff */ "pthread_create", "pthread_setspecific", @@ -224,6 +225,7 @@ char *whitelist[] = { "getpwent_r", "setpwent", "endpwent", + "getspnam_r", /* ignore dlopen, as we do not dlclose to get proper leak reports */ "dlopen", "dlerror", @@ -396,6 +398,35 @@ METHOD(leak_detective_t, report, void, } } +METHOD(leak_detective_t, set_state, bool, + private_leak_detective_t *this, bool enable) +{ + static struct sched_param oldparams; + static int oldpolicy; + struct sched_param params; + pthread_t thread_id; + + if (enable == installed) + { + return installed; + } + thread_id = pthread_self(); + if (enable) + { + install_hooks(); + pthread_setschedparam(thread_id, oldpolicy, &oldparams); + } + else + { + pthread_getschedparam(thread_id, &oldpolicy, &oldparams); + params.__sched_priority = sched_get_priority_max(SCHED_FIFO); + pthread_setschedparam(thread_id, SCHED_FIFO, ¶ms); + uninstall_hooks(); + } + installed = enable; + return !installed; +} + METHOD(leak_detective_t, usage, void, private_leak_detective_t *this, FILE *out) { @@ -444,7 +475,7 @@ void *malloc_hook(size_t bytes, const void *caller) hdr->magic = MEMORY_HEADER_MAGIC; hdr->bytes = bytes; - hdr->backtrace = backtrace_create(3); + hdr->backtrace = backtrace_create(2); tail->magic = MEMORY_TAIL_MAGIC; install_hooks(); @@ -513,7 +544,7 @@ void free_hook(void *ptr, const void *caller) /* memory was not allocated by our hooks */ fprintf(stderr, "freeing invalid memory (%p)", ptr); } - backtrace = backtrace_create(3); + backtrace = backtrace_create(2); backtrace->log(backtrace, stderr, TRUE); backtrace->destroy(backtrace); } @@ -569,15 +600,17 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) if (hdr->magic != MEMORY_HEADER_MAGIC || tail->magic != MEMORY_TAIL_MAGIC) { - fprintf(stderr, "reallocating invalid memory (%p): " - "header magic 0x%x, tail magic 0x%x:\n", - old, hdr->magic, tail->magic); - backtrace = backtrace_create(3); + fprintf(stderr, "reallocating invalid memory (%p):\n" + "header magic 0x%x:\n", old, hdr->magic); + backtrace = backtrace_create(2); backtrace->log(backtrace, stderr, TRUE); backtrace->destroy(backtrace); } - /* clear tail magic, allocate, set tail magic */ - memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); + else + { + /* clear tail magic, allocate, set tail magic */ + memset(&tail->magic, MEMORY_ALLOC_PATTERN, sizeof(tail->magic)); + } hdr = realloc(hdr, sizeof(memory_header_t) + bytes + sizeof(memory_tail_t)); tail = ((void*)hdr) + bytes + sizeof(memory_header_t); tail->magic = MEMORY_TAIL_MAGIC; @@ -585,7 +618,7 @@ void *realloc_hook(void *old, size_t bytes, const void *caller) /* update statistics */ hdr->bytes = bytes; hdr->backtrace->destroy(hdr->backtrace); - hdr->backtrace = backtrace_create(3); + hdr->backtrace = backtrace_create(2); /* update header of linked list neighbours */ if (hdr->next) @@ -619,6 +652,7 @@ leak_detective_t *leak_detective_create() .public = { .report = _report, .usage = _usage, + .set_state = _set_state, .destroy = _destroy, }, ); diff --git a/src/libstrongswan/utils/leak_detective.h b/src/libstrongswan/utils/leak_detective.h index 8c80d2532..55d7e44d9 100644 --- a/src/libstrongswan/utils/leak_detective.h +++ b/src/libstrongswan/utils/leak_detective.h @@ -49,6 +49,14 @@ struct leak_detective_t { */ void (*usage)(leak_detective_t *this, FILE *out); + /** + * Enable/disable leak detective hooks. + * + * @param TRUE to enable, FALSE to disable + * @return state active before calling set_state + */ + bool (*set_state)(leak_detective_t *this, bool enabled); + /** * Destroy a leak_detective instance. */ diff --git a/src/libstrongswan/utils/linked_list.c b/src/libstrongswan/utils/linked_list.c index 59d416f2f..1ff80999b 100644 --- a/src/libstrongswan/utils/linked_list.c +++ b/src/libstrongswan/utils/linked_list.c @@ -16,6 +16,7 @@ */ #include +#include #include "linked_list.h" @@ -572,3 +573,43 @@ linked_list_t *linked_list_create() return &this->public; } + +/* + * See header. + */ +linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator) +{ + linked_list_t *list; + void *item; + + list = linked_list_create(); + + while (enumerator->enumerate(enumerator, &item)) + { + list->insert_last(list, item); + } + enumerator->destroy(enumerator); + + return list; +} + +/* + * See header. + */ +linked_list_t *linked_list_create_with_items(void *item, ...) +{ + linked_list_t *list; + va_list args; + + list = linked_list_create(); + + va_start(args, item); + while (item) + { + list->insert_last(list, item); + item = va_arg(args, void*); + } + va_end(args); + + return list; +} diff --git a/src/libstrongswan/utils/linked_list.h b/src/libstrongswan/utils/linked_list.h index 293ca8661..1b5518480 100644 --- a/src/libstrongswan/utils/linked_list.h +++ b/src/libstrongswan/utils/linked_list.h @@ -299,4 +299,21 @@ struct linked_list_t { */ linked_list_t *linked_list_create(void); +/** + * Creates a linked list from an enumerator. + * + * @param enumerator enumerator over void*, gets destroyed + * @return linked_list_t object, containing enumerated values + */ +linked_list_t *linked_list_create_from_enumerator(enumerator_t *enumerator); + +/** + * Creates a linked list from a NULL terminated vararg list of items. + * + * @param first first item + * @param ... subsequent items, terminated by NULL + * @return linked_list_t object, containing passed items + */ +linked_list_t *linked_list_create_with_items(void *first, ...); + #endif /** LINKED_LIST_H_ @}*/ diff --git a/src/libstrongswan/utils/packet.c b/src/libstrongswan/utils/packet.c new file mode 100644 index 000000000..a2c329d60 --- /dev/null +++ b/src/libstrongswan/utils/packet.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "packet.h" + +typedef struct private_packet_t private_packet_t; + +/** + * Private data of an packet_t object. + */ +struct private_packet_t { + + /** + * Public part of a packet_t object. + */ + packet_t public; + + /** + * source address + */ + host_t *source; + + /** + * destination address + */ + host_t *destination; + + /** + * message data + */ + chunk_t data; + + /** + * actual chunk returned from get_data, adjusted when skip_bytes is called + */ + chunk_t adjusted_data; +}; + +METHOD(packet_t, set_source, void, + private_packet_t *this, host_t *source) +{ + DESTROY_IF(this->source); + this->source = source; +} + +METHOD(packet_t, set_destination, void, + private_packet_t *this, host_t *destination) +{ + DESTROY_IF(this->destination); + this->destination = destination; +} + +METHOD(packet_t, get_source, host_t*, + private_packet_t *this) +{ + return this->source; +} + +METHOD(packet_t, get_destination, host_t*, + private_packet_t *this) +{ + return this->destination; +} + +METHOD(packet_t, get_data, chunk_t, + private_packet_t *this) +{ + return this->adjusted_data; +} + +METHOD(packet_t, set_data, void, + private_packet_t *this, chunk_t data) +{ + free(this->data.ptr); + this->adjusted_data = this->data = data; +} + +METHOD(packet_t, skip_bytes, void, + private_packet_t *this, size_t bytes) +{ + this->adjusted_data = chunk_skip(this->adjusted_data, bytes); +} + +METHOD(packet_t, destroy, void, + private_packet_t *this) +{ + DESTROY_IF(this->source); + DESTROY_IF(this->destination); + free(this->data.ptr); + free(this); +} + +METHOD(packet_t, clone_, packet_t*, + private_packet_t *this) +{ + packet_t *other; + + other = packet_create(); + if (this->destination) + { + other->set_destination(other, + this->destination->clone(this->destination)); + } + if (this->source) + { + other->set_source(other, this->source->clone(this->source)); + } + if (this->data.ptr) + { + other->set_data(other, chunk_clone(this->adjusted_data)); + } + return other; +} + +/** + * Described in header. + */ +packet_t *packet_create_from_data(host_t *src, host_t *dst, chunk_t data) +{ + private_packet_t *this; + + INIT(this, + .public = { + .set_data = _set_data, + .get_data = _get_data, + .set_source = _set_source, + .get_source = _get_source, + .set_destination = _set_destination, + .get_destination = _get_destination, + .skip_bytes = _skip_bytes, + .clone = _clone_, + .destroy = _destroy, + }, + .source = src, + .destination = dst, + .adjusted_data = data, + .data = data, + ); + + return &this->public; +} + +/* + * Described in header. + */ +packet_t *packet_create() +{ + return packet_create_from_data(NULL, NULL, chunk_empty); +} diff --git a/src/libstrongswan/utils/packet.h b/src/libstrongswan/utils/packet.h new file mode 100644 index 000000000..5c4440115 --- /dev/null +++ b/src/libstrongswan/utils/packet.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup packet packet + * @{ @ingroup utils + */ + +#ifndef PACKET_H_ +#define PACKET_H_ + +typedef struct packet_t packet_t; + +#include +#include + +/** + * Abstraction of an IP/UDP-Packet, contains data, sender and receiver. + */ +struct packet_t { + + /** + * Set the source address. + * + * @param source address to set as source (gets owned) + */ + void (*set_source)(packet_t *packet, host_t *source); + + /** + * Set the destination address. + * + * @param source address to set as destination (gets owned) + */ + void (*set_destination)(packet_t *packet, host_t *destination); + + /** + * Get the source address. + * + * @return source address (internal data) + */ + host_t *(*get_source)(packet_t *packet); + + /** + * Get the destination address. + * + * @return destination address (internal data) + */ + host_t *(*get_destination)(packet_t *packet); + + /** + * Get the data from the packet. + * + * @return chunk containing the data (internal data) + */ + chunk_t (*get_data)(packet_t *packet); + + /** + * Set the data in the packet. + * + * @param data chunk with data to set (gets owned) + */ + void (*set_data)(packet_t *packet, chunk_t data); + + /** + * Increase the offset where the actual packet data starts. + * + * The total offset applies to future calls of get_data() and clone(). + * + * @note The offset is reset to 0 when set_data() is called. + * + * @param bytes the number of additional bytes to skip + */ + void (*skip_bytes)(packet_t *packet, size_t bytes); + + /** + * Clones a packet_t object. + * + * @note Data is cloned without skipped bytes. + * + * @param clone clone of the packet + */ + packet_t* (*clone)(packet_t *packet); + + /** + * Destroy the packet, freeing contained data. + */ + void (*destroy)(packet_t *packet); +}; + +/** + * Create an empty packet + * + * @return packet_t object + */ +packet_t *packet_create(); + +/** + * Create a packet from the supplied data + * + * @param src source address (gets owned) + * @param dst destination address (gets owned) + * @param data packet data (gets owned) + * @return packet_t object + */ +packet_t *packet_create_from_data(host_t *src, host_t *dst, chunk_t data); + +#endif /** PACKET_H_ @}*/ diff --git a/src/libstrongswan/utils/tun_device.c b/src/libstrongswan/utils/tun_device.c new file mode 100644 index 000000000..36f3359c0 --- /dev/null +++ b/src/libstrongswan/utils/tun_device.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * Copyright (C) 2012 Martin Willi + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __APPLE__ +#include +#include +#include +#elif defined(__linux__) +#include +#else +#include +#endif + +#include "tun_device.h" + +#include +#include +#include + +#define TUN_DEFAULT_MTU 1500 + +typedef struct private_tun_device_t private_tun_device_t; + +struct private_tun_device_t { + + /** + * Public interface + */ + tun_device_t public; + + /** + * The TUN device's file descriptor + */ + int tunfd; + + /** + * Name of the TUN device + */ + char if_name[IFNAMSIZ]; + + /** + * Socket used for ioctl() to set interface addr, ... + */ + int sock; + + /** + * The current MTU + */ + int mtu; +}; + +/** + * Set the sockaddr_t from the given netmask + */ +static void set_netmask(struct ifreq *ifr, int family, u_int8_t netmask) +{ + int len, bytes, bits; + char *target; + + switch (family) + { + case AF_INET: + { + struct sockaddr_in *addr = (struct sockaddr_in*)&ifr->ifr_addr; + addr->sin_family = AF_INET; + target = (char*)&addr->sin_addr; + len = 4; + break; + } + case AF_INET6: + { + struct sockaddr_in6 *addr = (struct sockaddr_in6*)&ifr->ifr_addr; + addr->sin6_family = AF_INET6; + target = (char*)&addr->sin6_addr; + len = 16; + break; + } + default: + return; + } + + bytes = (netmask + 7) / 8; + bits = (bytes * 8) - netmask; + + memset(target, 0xff, bytes); + memset(target + bytes, 0x00, len - bytes); + target[bytes - 1] = bits ? (u_int8_t)(0xff << bits) : 0xff; +} + +METHOD(tun_device_t, set_address, bool, + private_tun_device_t *this, host_t *addr, u_int8_t netmask) +{ + struct ifreq ifr; + int family; + + family = addr->get_family(addr); + if ((netmask > 32 && family == AF_INET) || netmask > 128) + { + DBG1(DBG_LIB, "failed to set address on %s: invalid netmask", + this->if_name); + return FALSE; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + memcpy(&ifr.ifr_addr, addr->get_sockaddr(addr), sizeof(sockaddr_t)); + + if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set address on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } +#ifdef __APPLE__ + if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set dest address on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } +#endif /* __APPLE__ */ + + set_netmask(&ifr, family, netmask); + + if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set netmask on %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } + return TRUE; +} + +METHOD(tun_device_t, up, bool, + private_tun_device_t *this) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + + if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name, + strerror(errno)); + return FALSE; + } + + ifr.ifr_flags |= IFF_RUNNING | IFF_UP; + + if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name, + strerror(errno)); + return FALSE; + } + return TRUE; +} + +METHOD(tun_device_t, set_mtu, bool, + private_tun_device_t *this, int mtu) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + ifr.ifr_mtu = mtu; + + if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name, + strerror(errno)); + return FALSE; + } + this->mtu = mtu; + return TRUE; +} + +METHOD(tun_device_t, get_mtu, int, + private_tun_device_t *this) +{ + struct ifreq ifr; + + if (this->mtu > 0) + { + return this->mtu; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + this->mtu = TUN_DEFAULT_MTU; + + if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0) + { + this->mtu = ifr.ifr_mtu; + } + return this->mtu; +} + +METHOD(tun_device_t, get_name, char*, + private_tun_device_t *this) +{ + return this->if_name; +} + +METHOD(tun_device_t, write_packet, bool, + private_tun_device_t *this, chunk_t packet) +{ + ssize_t s; + + s = write(this->tunfd, packet.ptr, packet.len); + if (s < 0) + { + DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s", + this->if_name, strerror(errno)); + return FALSE; + } + else if (s != packet.len) + { + return FALSE; + } + return TRUE; +} + +METHOD(tun_device_t, read_packet, bool, + private_tun_device_t *this, chunk_t *packet) +{ + ssize_t len; + fd_set set; + bool old; + + FD_ZERO(&set); + FD_SET(this->tunfd, &set); + + old = thread_cancelability(TRUE); + len = select(this->tunfd + 1, &set, NULL, NULL, NULL); + thread_cancelability(old); + + if (len < 0) + { + DBG1(DBG_LIB, "select on TUN device %s failed: %s", this->if_name, + strerror(errno)); + return FALSE; + } + /* FIXME: this is quite expensive for lots of small packets, copy from + * local buffer instead? */ + *packet = chunk_alloc(get_mtu(this)); + len = read(this->tunfd, packet->ptr, packet->len); + if (len < 0) + { + DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name, + strerror(errno)); + chunk_free(packet); + return FALSE; + } + packet->len = len; + return TRUE; +} + +METHOD(tun_device_t, destroy, void, + private_tun_device_t *this) +{ + if (this->tunfd > 0) + { + close(this->tunfd); +#ifdef __FreeBSD__ + /* tun(4) says the following: "These network interfaces persist until + * the if_tun.ko module is unloaded, or until removed with the + * ifconfig(8) command." So simply closing the FD is not enough. */ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0) + { + DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name, + strerror(errno)); + } +#endif /* __FreeBSD__ */ + } + if (this->sock > 0) + { + close(this->sock); + } + free(this); +} + +/** + * Initialize the tun device + */ +static bool init_tun(private_tun_device_t *this, const char *name_tmpl) +{ +#ifdef __APPLE__ + + struct ctl_info info; + struct sockaddr_ctl addr; + socklen_t size = IFNAMSIZ; + + memset(&info, 0, sizeof(info)); + memset(&addr, 0, sizeof(addr)); + + this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + if (this->tunfd < 0) + { + DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s", + strerror(errno)); + return FALSE; + } + + /* get a control identifier for the utun kernel extension */ + strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME)); + if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0) + { + DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + + addr.sc_id = info.ctl_id; + addr.sc_len = sizeof(addr); + addr.sc_family = AF_SYSTEM; + addr.ss_sysaddr = AF_SYS_CONTROL; + /* allocate identifier dynamically */ + addr.sc_unit = 0; + + if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, + this->if_name, &size) < 0) + { + DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + return TRUE; + +#elif defined(IFF_TUN) + + struct ifreq ifr; + + strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ); + this->if_name[IFNAMSIZ-1] = '\0'; + + this->tunfd = open("/dev/net/tun", O_RDWR); + if (this->tunfd < 0) + { + DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno)); + return FALSE; + } + + memset(&ifr, 0, sizeof(ifr)); + + /* TUN device, no packet info */ + ifr.ifr_flags = IFF_TUN | IFF_NO_PI; + + strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ); + if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0) + { + DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno)); + close(this->tunfd); + return FALSE; + } + strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ); + return TRUE; + +#else /* !IFF_TUN */ + + /* this works on FreeBSD and might also work on Linux with older TUN + * driver versions (no IFF_TUN) */ + char devname[IFNAMSIZ]; + int i; + + if (name_tmpl) + { + DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported"); + } + + for (i = 0; i < 256; i++) + { + snprintf(devname, IFNAMSIZ, "/dev/tun%d", i); + this->tunfd = open(devname, O_RDWR); + if (this->tunfd > 0) + { /* for ioctl(2) calls only the interface name is used */ + snprintf(this->if_name, IFNAMSIZ, "tun%d", i); + break; + } + DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno)); + } + return this->tunfd > 0; + +#endif /* !__APPLE__ */ +} + +/* + * Described in header + */ +tun_device_t *tun_device_create(const char *name_tmpl) +{ + private_tun_device_t *this; + + INIT(this, + .public = { + .read_packet = _read_packet, + .write_packet = _write_packet, + .get_mtu = _get_mtu, + .set_mtu = _set_mtu, + .get_name = _get_name, + .set_address = _set_address, + .up = _up, + .destroy = _destroy, + }, + .tunfd = -1, + .sock = -1, + ); + + if (!init_tun(this, name_tmpl)) + { + free(this); + return NULL; + } + DBG1(DBG_LIB, "created TUN device: %s", this->if_name); + + this->sock = socket(AF_INET, SOCK_DGRAM, 0); + if (this->sock < 0) + { + DBG1(DBG_LIB, "failed to open socket to configure TUN device"); + destroy(this); + return NULL; + } + return &this->public; +} diff --git a/src/libstrongswan/utils/tun_device.h b/src/libstrongswan/utils/tun_device.h new file mode 100644 index 000000000..71af0386b --- /dev/null +++ b/src/libstrongswan/utils/tun_device.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012 Giuliano Grassi + * Copyright (C) 2012 Ralf Sager + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup tun_device tun_device + * @{ @ingroup utils + */ + +#ifndef TUN_DEVICE_H_ +#define TUN_DEVICE_H_ + +#include +#include + +typedef struct tun_device_t tun_device_t; + +/** + * Class to create TUN devices + * + * Creating such a device requires the CAP_NET_ADMIN capability. + * + * @note The implementation is currently very Linux specific + */ +struct tun_device_t { + + /** + * Read a packet from the TUN device + * + * @note This call blocks until a packet is available. It is a thread + * cancellation point. + * + * @param packet the packet read from the device + * @return TRUE if successful + */ + bool (*read_packet)(tun_device_t *this, chunk_t *packet); + + /** + * Write a packet to the TUN device + * + * @param packet the packet to write to the TUN device + * @return TRUE if successful + */ + bool (*write_packet)(tun_device_t *this, chunk_t packet); + + /** + * Set the IP address of the device + * + * @param addr the desired interface address + * @param netmask the netmask to use + * @return TRUE if operation successful + */ + bool (*set_address)(tun_device_t *this, host_t *addr, u_int8_t netmask); + + /** + * Bring the TUN device up + * + * @return TRUE if operation successful + */ + bool (*up)(tun_device_t *this); + + /** + * Set the MTU for this TUN device + * + * @param mtu new MTU + * @return TRUE if operation successful + */ + bool (*set_mtu)(tun_device_t *this, int mtu); + + /** + * Get the current MTU for this TUN device + * + * @return current MTU + */ + int (*get_mtu)(tun_device_t *this); + + /** + * Get the interface name of this device + * + * @return interface name + */ + char *(*get_name)(tun_device_t *this); + + /** + * Destroy a tun_device_t + */ + void (*destroy)(tun_device_t *this); + +}; + +/** + * Create a TUN device using the given name template. + * + * @param name_tmpl name template, defaults to "tun%d" if not given + * @return TUN device + */ +tun_device_t *tun_device_create(const char *name_tmpl); + +#endif /** TUN_DEVICE_H_ @}*/ diff --git a/src/libtls/Makefile.am b/src/libtls/Makefile.am index 4cc1a1bdb..772950606 100644 --- a/src/libtls/Makefile.am +++ b/src/libtls/Makefile.am @@ -3,15 +3,14 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan ipseclib_LTLIBRARIES = libtls.la libtls_la_SOURCES = \ - tls_protection.h tls_protection.c \ - tls_compression.h tls_compression.c \ - tls_fragmentation.h tls_fragmentation.c \ - tls_alert.h tls_alert.c \ - tls_crypto.h tls_crypto.c \ - tls_prf.h tls_prf.c \ - tls_socket.h tls_socket.c \ - tls_eap.h tls_eap.c \ - tls_cache.h tls_cache.c \ - tls_peer.h tls_peer.c \ - tls_server.h tls_server.c \ - tls_handshake.h tls_application.h tls.h tls.c + tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \ + tls_crypto.c tls_prf.c tls_socket.c tls_eap.c tls_cache.c tls_peer.c \ + tls_server.c tls.c + +if USE_DEV_HEADERS +tls_includedir = ${dev_headers}/tls +nobase_tls_include_HEADERS = \ + tls_protection.h tls_compression.h tls_fragmentation.h tls_alert.h \ + tls_crypto.h tls_prf.h tls_socket.h tls_eap.h tls_cache.h tls_peer.h \ + tls_server.h tls_handshake.h tls_application.h tls.h +endif diff --git a/src/libtls/Makefile.in b/src/libtls/Makefile.in index 844b65156..fb1136ee0 100644 --- a/src/libtls/Makefile.in +++ b/src/libtls/Makefile.in @@ -15,6 +15,7 @@ @SET_MAKE@ + VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ @@ -35,7 +36,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/libtls -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +DIST_COMMON = $(am__nobase_tls_include_HEADERS_DIST) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ $(top_srcdir)/m4/config/ltoptions.m4 \ @@ -49,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -72,7 +75,8 @@ am__nobase_list = $(am__nobase_strip_setup); \ am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(ipseclibdir)" +am__installdirs = "$(DESTDIR)$(ipseclibdir)" \ + "$(DESTDIR)$(tls_includedir)" LTLIBRARIES = $(ipseclib_LTLIBRARIES) libtls_la_LIBADD = am_libtls_la_OBJECTS = tls_protection.lo tls_compression.lo \ @@ -80,7 +84,7 @@ am_libtls_la_OBJECTS = tls_protection.lo tls_compression.lo \ tls_socket.lo tls_eap.lo tls_cache.lo tls_peer.lo \ tls_server.lo tls.lo libtls_la_OBJECTS = $(am_libtls_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -95,6 +99,11 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libtls_la_SOURCES) DIST_SOURCES = $(libtls_la_SOURCES) +am__nobase_tls_include_HEADERS_DIST = tls_protection.h \ + tls_compression.h tls_fragmentation.h tls_alert.h tls_crypto.h \ + tls_prf.h tls_socket.h tls_eap.h tls_cache.h tls_peer.h \ + tls_server.h tls_handshake.h tls_application.h tls.h +HEADERS = $(nobase_tls_include_HEADERS) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -106,6 +115,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -200,11 +210,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -221,11 +234,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -241,6 +255,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -250,7 +265,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ @@ -281,18 +295,15 @@ xml_LIBS = @xml_LIBS@ INCLUDES = -I$(top_srcdir)/src/libstrongswan ipseclib_LTLIBRARIES = libtls.la libtls_la_SOURCES = \ - tls_protection.h tls_protection.c \ - tls_compression.h tls_compression.c \ - tls_fragmentation.h tls_fragmentation.c \ - tls_alert.h tls_alert.c \ - tls_crypto.h tls_crypto.c \ - tls_prf.h tls_prf.c \ - tls_socket.h tls_socket.c \ - tls_eap.h tls_eap.c \ - tls_cache.h tls_cache.c \ - tls_peer.h tls_peer.c \ - tls_server.h tls_server.c \ - tls_handshake.h tls_application.h tls.h tls.c + tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \ + tls_crypto.c tls_prf.c tls_socket.c tls_eap.c tls_cache.c tls_peer.c \ + tls_server.c tls.c + +@USE_DEV_HEADERS_TRUE@tls_includedir = ${dev_headers}/tls +@USE_DEV_HEADERS_TRUE@nobase_tls_include_HEADERS = \ +@USE_DEV_HEADERS_TRUE@ tls_protection.h tls_compression.h tls_fragmentation.h tls_alert.h \ +@USE_DEV_HEADERS_TRUE@ tls_crypto.h tls_prf.h tls_socket.h tls_eap.h tls_cache.h tls_peer.h \ +@USE_DEV_HEADERS_TRUE@ tls_server.h tls_handshake.h tls_application.h tls.h all: all-am @@ -407,6 +418,29 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs +install-nobase_tls_includeHEADERS: $(nobase_tls_include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(tls_includedir)" || $(MKDIR_P) "$(DESTDIR)$(tls_includedir)" + @list='$(nobase_tls_include_HEADERS)'; test -n "$(tls_includedir)" || list=; \ + $(am__nobase_list) | while read dir files; do \ + xfiles=; for file in $$files; do \ + if test -f "$$file"; then xfiles="$$xfiles $$file"; \ + else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ + test -z "$$xfiles" || { \ + test "x$$dir" = x. || { \ + echo "$(MKDIR_P) '$(DESTDIR)$(tls_includedir)/$$dir'"; \ + $(MKDIR_P) "$(DESTDIR)$(tls_includedir)/$$dir"; }; \ + echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(tls_includedir)/$$dir'"; \ + $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(tls_includedir)/$$dir" || exit $$?; }; \ + done + +uninstall-nobase_tls_includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(nobase_tls_include_HEADERS)'; test -n "$(tls_includedir)" || list=; \ + $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(tls_includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(tls_includedir)" && rm -f $$files ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ @@ -492,9 +526,9 @@ distdir: $(DISTFILES) done check-am: all-am check: check-am -all-am: Makefile $(LTLIBRARIES) +all-am: Makefile $(LTLIBRARIES) $(HEADERS) installdirs: - for dir in "$(DESTDIR)$(ipseclibdir)"; do \ + for dir in "$(DESTDIR)$(ipseclibdir)" "$(DESTDIR)$(tls_includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -545,7 +579,8 @@ info: info-am info-am: -install-data-am: install-ipseclibLTLIBRARIES +install-data-am: install-ipseclibLTLIBRARIES \ + install-nobase_tls_includeHEADERS install-dvi: install-dvi-am @@ -591,7 +626,8 @@ ps: ps-am ps-am: -uninstall-am: uninstall-ipseclibLTLIBRARIES +uninstall-am: uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_tls_includeHEADERS .MAKE: install-am install-strip @@ -602,12 +638,14 @@ uninstall-am: uninstall-ipseclibLTLIBRARIES install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am \ - install-ipseclibLTLIBRARIES install-man install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ + install-ipseclibLTLIBRARIES install-man \ + install-nobase_tls_includeHEADERS install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES + tags uninstall uninstall-am uninstall-ipseclibLTLIBRARIES \ + uninstall-nobase_tls_includeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. diff --git a/src/libtls/tls.h b/src/libtls/tls.h index e22b0facc..6b4876f73 100644 --- a/src/libtls/tls.h +++ b/src/libtls/tls.h @@ -26,6 +26,12 @@ #ifndef TLS_H_ #define TLS_H_ +/** + * Maximum size of a TLS fragment + * as defined by section 6.2.1. "Fragmentation" of RFC 5246 TLS 1.2 + */ +#define TLS_MAX_FRAGMENT_LEN 16384 + typedef enum tls_version_t tls_version_t; typedef enum tls_content_type_t tls_content_type_t; typedef enum tls_handshake_type_t tls_handshake_type_t; diff --git a/src/libtls/tls_crypto.c b/src/libtls/tls_crypto.c index 4d84876d0..f74984879 100644 --- a/src/libtls/tls_crypto.c +++ b/src/libtls/tls_crypto.c @@ -1196,12 +1196,12 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) return FALSE; } hasher = lib->crypto->create_hasher(lib->crypto, alg->hash); - if (!hasher) + if (!hasher || !hasher->allocate_hash(hasher, data, hash)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, alg->hash); + DESTROY_IF(hasher); return FALSE; } - hasher->allocate_hash(hasher, data, hash); hasher->destroy(hasher); } else @@ -1210,20 +1210,20 @@ static bool hash_data(private_tls_crypto_t *this, chunk_t data, chunk_t *hash) char buf[HASH_SIZE_MD5 + HASH_SIZE_SHA1]; md5 = lib->crypto->create_hasher(lib->crypto, HASH_MD5); - if (!md5) + if (!md5 || !md5->get_hash(md5, data, buf)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_MD5); + DESTROY_IF(md5); return FALSE; } - md5->get_hash(md5, data, buf); md5->destroy(md5); sha1 = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!sha1) + if (!sha1 || !sha1->get_hash(sha1, data, buf + HASH_SIZE_MD5)) { DBG1(DBG_TLS, "%N not supported", hash_algorithm_names, HASH_SHA1); + DESTROY_IF(sha1); return FALSE; } - sha1->get_hash(sha1, data, buf + HASH_SIZE_MD5); sha1->destroy(sha1); *hash = chunk_clone(chunk_from_thing(buf)); @@ -1462,7 +1462,11 @@ METHOD(tls_crypto_t, calculate_finished, bool, { return FALSE; } - this->prf->get_bytes(this->prf, label, seed, 12, out); + if (!this->prf->get_bytes(this->prf, label, seed, 12, out)) + { + free(seed.ptr); + return FALSE; + } free(seed.ptr); return TRUE; } @@ -1470,7 +1474,7 @@ METHOD(tls_crypto_t, calculate_finished, bool, /** * Derive master secret from premaster, optionally save session */ -static void derive_master(private_tls_crypto_t *this, chunk_t premaster, +static bool derive_master(private_tls_crypto_t *this, chunk_t premaster, chunk_t session, identification_t *id, chunk_t client_random, chunk_t server_random) { @@ -1479,23 +1483,28 @@ static void derive_master(private_tls_crypto_t *this, chunk_t premaster, /* derive master secret */ seed = chunk_cata("cc", client_random, server_random); - this->prf->set_key(this->prf, premaster); - this->prf->get_bytes(this->prf, "master secret", seed, - sizeof(master), master); - this->prf->set_key(this->prf, chunk_from_thing(master)); + if (!this->prf->set_key(this->prf, premaster) || + !this->prf->get_bytes(this->prf, "master secret", seed, + sizeof(master), master) || + !this->prf->set_key(this->prf, chunk_from_thing(master))) + { + return FALSE; + } + if (this->cache && session.len) { this->cache->create(this->cache, session, id, chunk_from_thing(master), this->suite); } memwipe(master, sizeof(master)); + return TRUE; } /** * Expand key material from master secret */ -static void expand_keys(private_tls_crypto_t *this, +static bool expand_keys(private_tls_crypto_t *this, chunk_t client_random, chunk_t server_random) { chunk_t seed, block, client_write, server_write; @@ -1513,7 +1522,11 @@ static void expand_keys(private_tls_crypto_t *this, } seed = chunk_cata("cc", server_random, client_random); block = chunk_alloca((mks + eks + ivs) * 2); - this->prf->get_bytes(this->prf, "key expansion", seed, block.len, block.ptr); + if (!this->prf->get_bytes(this->prf, "key expansion", seed, + block.len, block.ptr)) + { + return FALSE; + } /* signer keys */ client_write = chunk_create(block.ptr, mks); @@ -1522,13 +1535,19 @@ static void expand_keys(private_tls_crypto_t *this, block = chunk_skip(block, mks); if (this->tls->is_server(this->tls)) { - this->signer_in->set_key(this->signer_in, client_write); - this->signer_out->set_key(this->signer_out, server_write); + if (!this->signer_in->set_key(this->signer_in, client_write) || + !this->signer_out->set_key(this->signer_out, server_write)) + { + return FALSE; + } } else { - this->signer_out->set_key(this->signer_out, client_write); - this->signer_in->set_key(this->signer_in, server_write); + if (!this->signer_out->set_key(this->signer_out, client_write) || + !this->signer_in->set_key(this->signer_in, server_write)) + { + return FALSE; + } } /* crypter keys, and IVs if < TLSv1.2 */ @@ -1541,13 +1560,19 @@ static void expand_keys(private_tls_crypto_t *this, if (this->tls->is_server(this->tls)) { - this->crypter_in->set_key(this->crypter_in, client_write); - this->crypter_out->set_key(this->crypter_out, server_write); + if (!this->crypter_in->set_key(this->crypter_in, client_write) || + !this->crypter_out->set_key(this->crypter_out, server_write)) + { + return FALSE; + } } else { - this->crypter_out->set_key(this->crypter_out, client_write); - this->crypter_in->set_key(this->crypter_in, server_write); + if (!this->crypter_out->set_key(this->crypter_out, client_write) || + !this->crypter_in->set_key(this->crypter_in, server_write)) + { + return FALSE; + } } if (ivs) { @@ -1574,17 +1599,22 @@ static void expand_keys(private_tls_crypto_t *this, { seed = chunk_cata("cc", client_random, server_random); this->msk = chunk_alloc(64); - this->prf->get_bytes(this->prf, this->msk_label, seed, - this->msk.len, this->msk.ptr); + if (!this->prf->get_bytes(this->prf, this->msk_label, seed, + this->msk.len, this->msk.ptr)) + { + return FALSE; + } } + return TRUE; } -METHOD(tls_crypto_t, derive_secrets, void, +METHOD(tls_crypto_t, derive_secrets, bool, private_tls_crypto_t *this, chunk_t premaster, chunk_t session, identification_t *id, chunk_t client_random, chunk_t server_random) { - derive_master(this, premaster, session, id, client_random, server_random); - expand_keys(this, client_random, server_random); + return derive_master(this, premaster, session, id, + client_random, server_random) && + expand_keys(this, client_random, server_random); } METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t, @@ -1601,8 +1631,11 @@ METHOD(tls_crypto_t, resume_session, tls_cipher_suite_t, this->suite = select_cipher_suite(this, &this->suite, 1, KEY_ANY); if (this->suite) { - this->prf->set_key(this->prf, master); - expand_keys(this, client_random, server_random); + if (!this->prf->set_key(this->prf, master) || + !expand_keys(this, client_random, server_random)) + { + this->suite = 0; + } } chunk_clear(&master); } @@ -1719,11 +1752,14 @@ tls_crypto_t *tls_crypto_create(tls_t *tls, tls_cache_t *cache) switch (tls->get_purpose(tls)) { case TLS_PURPOSE_EAP_TLS: - case TLS_PURPOSE_EAP_PEAP: /* MSK PRF ASCII constant label according to EAP-TLS RFC 5216 */ this->msk_label = "client EAP encryption"; build_cipher_suite_list(this, FALSE); break; + case TLS_PURPOSE_EAP_PEAP: + this->msk_label = "client EAP encryption"; + build_cipher_suite_list(this, TRUE); + break; case TLS_PURPOSE_EAP_TTLS: /* MSK PRF ASCII constant label according to EAP-TTLS RFC 5281 */ this->msk_label = "ttls keying material"; diff --git a/src/libtls/tls_crypto.h b/src/libtls/tls_crypto.h index 7430aea66..5512b1f48 100644 --- a/src/libtls/tls_crypto.h +++ b/src/libtls/tls_crypto.h @@ -515,8 +515,9 @@ struct tls_crypto_t { * @param id identity the session is bound to * @param client_random random data from client hello * @param server_random random data from server hello + * @return TRUE if secrets derived successfully */ - void (*derive_secrets)(tls_crypto_t *this, chunk_t premaster, + bool (*derive_secrets)(tls_crypto_t *this, chunk_t premaster, chunk_t session, identification_t *id, chunk_t client_random, chunk_t server_random); diff --git a/src/libtls/tls_eap.c b/src/libtls/tls_eap.c index 685904fdf..928aadcb3 100644 --- a/src/libtls/tls_eap.c +++ b/src/libtls/tls_eap.c @@ -21,8 +21,11 @@ #include #include -/** Size limit for a single TLS message */ -#define MAX_TLS_MESSAGE_LEN 65536 +/** + * Size limit for a TLS message allowing for worst-case protection overhead + * according to section 6.2.3. "Payload Protection" of RFC 5246 TLS 1.2 + */ +#define TLS_MAX_MESSAGE_LEN 4 * (TLS_MAX_FRAGMENT_LEN + 2048) typedef struct private_tls_eap_t private_tls_eap_t; @@ -79,7 +82,7 @@ struct private_tls_eap_t { int processed; /** - * Maximum number of processed EAP messages/fragments + * Maximum number of processed EAP messages/fragments */ int max_msg_count; }; @@ -138,7 +141,7 @@ METHOD(tls_eap_t, initiate, status_t, *out = chunk_clone(chunk_from_thing(pkt)); DBG2(DBG_TLS, "sending %N start packet (%u bytes)", - eap_type_names, this->type, sizeof(eap_tls_packet_t)); + eap_type_names, this->type, sizeof(eap_tls_packet_t)); DBG3(DBG_TLS, "%B", out); return NEED_MORE; } @@ -150,10 +153,12 @@ METHOD(tls_eap_t, initiate, status_t, */ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt) { - u_int32_t msg_len; u_int16_t pkt_len; + u_int32_t msg_len; + size_t msg_len_offset = 0; pkt_len = untoh16(&pkt->length); + if (pkt->flags & EAP_TLS_LENGTH) { if (pkt_len < sizeof(eap_tls_packet_t) + sizeof(msg_len)) @@ -163,16 +168,17 @@ static status_t process_pkt(private_tls_eap_t *this, eap_tls_packet_t *pkt) } msg_len = untoh32(pkt + 1); if (msg_len < pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len) || - msg_len > MAX_TLS_MESSAGE_LEN) + msg_len > TLS_MAX_MESSAGE_LEN) { - DBG1(DBG_TLS, "invalid %N packet length", eap_type_names, this->type); + DBG1(DBG_TLS, "invalid %N packet length (%u bytes)", eap_type_names, + this->type, msg_len); return FAILED; } - return this->tls->process(this->tls, (char*)(pkt + 1) + sizeof(msg_len), - pkt_len - sizeof(eap_tls_packet_t) - sizeof(msg_len)); + msg_len_offset = sizeof(msg_len); } - return this->tls->process(this->tls, (char*)(pkt + 1), - pkt_len - sizeof(eap_tls_packet_t)); + + return this->tls->process(this->tls, (char*)(pkt + 1) + msg_len_offset, + pkt_len - sizeof(eap_tls_packet_t) - msg_len_offset); } /** @@ -182,7 +188,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) { char buf[this->frag_size]; eap_tls_packet_t *pkt; - size_t len, reclen; + size_t len, reclen, msg_len_offset; status_t status; char *kind; @@ -214,15 +220,16 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) if (this->first_fragment) { len = sizeof(buf) - sizeof(eap_tls_packet_t) - sizeof(u_int32_t); - status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) + - sizeof(u_int32_t), &len, &reclen); + msg_len_offset = sizeof(u_int32_t); } else { len = sizeof(buf) - sizeof(eap_tls_packet_t); - status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t), - &len, &reclen); + msg_len_offset = 0; } + status = this->tls->build(this->tls, buf + sizeof(eap_tls_packet_t) + + msg_len_offset, &len, &reclen); + switch (status) { case NEED_MORE: @@ -230,7 +237,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) kind = "further fragment"; if (this->first_fragment) { - pkt->flags |= EAP_TLS_LENGTH; + pkt->flags |= EAP_TLS_LENGTH; this->first_fragment = FALSE; kind = "first fragment"; } @@ -244,11 +251,15 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) } kind = "packet"; } - else + else if (this->type != EAP_TNC) { this->first_fragment = TRUE; kind = "final fragment"; } + else + { + kind = "packet"; + } break; default: return status; @@ -256,7 +267,7 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) if (reclen) { if (pkt->flags & EAP_TLS_LENGTH) - { + { htoun32(pkt + 1, reclen); len += sizeof(u_int32_t); pkt->flags |= EAP_TLS_LENGTH; @@ -264,15 +275,15 @@ static status_t build_pkt(private_tls_eap_t *this, chunk_t *out) else { /* get rid of the reserved length field */ - memcpy(buf+sizeof(eap_packet_t), - buf+sizeof(eap_packet_t)+sizeof(u_int32_t), len); + memmove(buf + sizeof(eap_tls_packet_t), + buf + sizeof(eap_tls_packet_t) + sizeof(u_int32_t), len); } } len += sizeof(eap_tls_packet_t); htoun16(&pkt->length, len); *out = chunk_clone(chunk_create(buf, len)); DBG2(DBG_TLS, "sending %N %s (%u bytes)", - eap_type_names, this->type, kind, len); + eap_type_names, this->type, kind, len); DBG3(DBG_TLS, "%B", out); return NEED_MORE; } @@ -319,7 +330,7 @@ METHOD(tls_eap_t, process, status_t, eap_tls_packet_t *pkt; status_t status; - if (++this->processed > this->max_msg_count) + if (this->max_msg_count && ++this->processed > this->max_msg_count) { DBG1(DBG_TLS, "%N packet count exceeded (%d > %d)", eap_type_names, this->type, @@ -441,7 +452,7 @@ tls_eap_t *tls_eap_create(eap_type_t type, tls_t *tls, size_t frag_size, }, .type = type, .is_server = tls->is_server(tls), - .first_fragment = TRUE, + .first_fragment = (type != EAP_TNC), .frag_size = frag_size, .max_msg_count = max_msg_count, .include_length = include_length, diff --git a/src/libtls/tls_fragmentation.c b/src/libtls/tls_fragmentation.c index 62e36aaec..f2fa77cfd 100644 --- a/src/libtls/tls_fragmentation.c +++ b/src/libtls/tls_fragmentation.c @@ -18,6 +18,11 @@ #include #include +/** + * Maximum size of a TLS handshake message we accept + */ +#define TLS_MAX_HANDSHAKE_LEN 65536 + typedef struct private_tls_fragmentation_t private_tls_fragmentation_t; /** @@ -93,16 +98,6 @@ struct private_tls_fragmentation_t { tls_application_t *application; }; -/** - * Maximum size of a TLS fragment - */ -#define MAX_TLS_FRAGMENT_LEN 16384 - -/** - * Maximum size of a TLS handshake message we accept - */ -#define MAX_TLS_HANDSHAKE_LEN 65536 - /** * Process a TLS alert */ @@ -134,7 +129,7 @@ static status_t process_handshake(private_tls_fragmentation_t *this, status_t status; chunk_t data; - if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN) + if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN) { DBG1(DBG_TLS, "TLS fragment has invalid length"); this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); @@ -151,7 +146,7 @@ static status_t process_handshake(private_tls_fragmentation_t *this, return NEED_MORE; } this->type = type; - if (len > MAX_TLS_HANDSHAKE_LEN) + if (len > TLS_MAX_HANDSHAKE_LEN) { DBG1(DBG_TLS, "TLS handshake exceeds maximum length"); this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); @@ -202,12 +197,18 @@ static status_t process_handshake(private_tls_fragmentation_t *this, static status_t process_application(private_tls_fragmentation_t *this, bio_reader_t *reader) { + if (!this->handshake->finished(this->handshake)) + { + DBG1(DBG_TLS, "received TLS application data, " + "but handshake not finished"); + return FAILED; + } while (reader->remaining(reader)) { status_t status; chunk_t data; - if (reader->remaining(reader) > MAX_TLS_FRAGMENT_LEN) + if (reader->remaining(reader) > TLS_MAX_FRAGMENT_LEN) { DBG1(DBG_TLS, "TLS fragment has invalid length"); this->alert->add(this->alert, TLS_FATAL, TLS_DECODE_ERROR); @@ -427,14 +428,14 @@ METHOD(tls_fragmentation_t, build, status_t, if (this->output.len) { *type = this->output_type; - if (this->output.len <= MAX_TLS_FRAGMENT_LEN) + if (this->output.len <= TLS_MAX_FRAGMENT_LEN) { *data = this->output; this->output = chunk_empty; return NEED_MORE; } - *data = chunk_create(this->output.ptr, MAX_TLS_FRAGMENT_LEN); - this->output = chunk_clone(chunk_skip(this->output, MAX_TLS_FRAGMENT_LEN)); + *data = chunk_create(this->output.ptr, TLS_MAX_FRAGMENT_LEN); + this->output = chunk_clone(chunk_skip(this->output, TLS_MAX_FRAGMENT_LEN)); return NEED_MORE; } return status; diff --git a/src/libtls/tls_peer.c b/src/libtls/tls_peer.c index 6091702cf..65072d087 100644 --- a/src/libtls/tls_peer.c +++ b/src/libtls/tls_peer.c @@ -709,13 +709,15 @@ static status_t send_client_hello(private_tls_peer_t *this, htoun32(&this->client_random, time(NULL)); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || + !rng->get_bytes(rng, sizeof(this->client_random) - 4, + this->client_random + 4)) { - DBG1(DBG_TLS, "no suitable RNG found to generate client random"); + DBG1(DBG_TLS, "failed to generate client random"); this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + DESTROY_IF(rng); return NEED_MORE; } - rng->get_bytes(rng, sizeof(this->client_random) - 4, this->client_random + 4); rng->destroy(rng); /* TLS version */ @@ -903,20 +905,24 @@ static status_t send_key_exchange_encrypt(private_tls_peer_t *this, chunk_t encrypted; rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (!rng) + if (!rng || !rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2)) { - DBG1(DBG_TLS, "no suitable RNG found for TLS premaster secret"); + DBG1(DBG_TLS, "failed to generate TLS premaster secret"); this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + DESTROY_IF(rng); return NEED_MORE; } - rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2); rng->destroy(rng); htoun16(premaster, TLS_1_2); - this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), - this->session, this->server, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), + this->session, this->server, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random))) + { + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + return NEED_MORE; + } public = find_public_key(this); if (!public) @@ -958,10 +964,15 @@ static status_t send_key_exchange_dhe(private_tls_peer_t *this, this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); return NEED_MORE; } - this->crypto->derive_secrets(this->crypto, premaster, - this->session, this->server, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + if (!this->crypto->derive_secrets(this->crypto, premaster, + this->session, this->server, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random))) + { + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + chunk_clear(&premaster); + return NEED_MORE; + } chunk_clear(&premaster); this->dh->get_my_public_value(this->dh, &pub); diff --git a/src/libtls/tls_prf.c b/src/libtls/tls_prf.c index f181d01d3..918de1e50 100644 --- a/src/libtls/tls_prf.c +++ b/src/libtls/tls_prf.c @@ -33,16 +33,16 @@ struct private_tls_prf12_t { prf_t *prf; }; -METHOD(tls_prf_t, set_key12, void, +METHOD(tls_prf_t, set_key12, bool, private_tls_prf12_t *this, chunk_t key) { - this->prf->set_key(this->prf, key); + return this->prf->set_key(this->prf, key); } /** * The P_hash function as in TLS 1.0/1.2 */ -static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size, +static bool p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size, size_t bytes, char *out) { char buf[block_size], abuf[block_size]; @@ -56,11 +56,17 @@ static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size, while (TRUE) { /* A(i) = HMAC_hash(secret, A(i-1)) */ - prf->get_bytes(prf, a, abuf); + if (!prf->get_bytes(prf, a, abuf)) + { + return FALSE; + } a = chunk_from_thing(abuf); /* HMAC_hash(secret, A(i) + seed) */ - prf->get_bytes(prf, a, NULL); - prf->get_bytes(prf, seed, buf); + if (!prf->get_bytes(prf, a, NULL) || + !prf->get_bytes(prf, seed, buf)) + { + return FALSE; + } if (bytes <= block_size) { @@ -71,14 +77,15 @@ static void p_hash(prf_t *prf, char *label, chunk_t seed, size_t block_size, out += block_size; bytes -= block_size; } + return TRUE; } -METHOD(tls_prf_t, get_bytes12, void, +METHOD(tls_prf_t, get_bytes12, bool, private_tls_prf12_t *this, char *label, chunk_t seed, size_t bytes, char *out) { - p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf), - bytes, out); + return p_hash(this->prf, label, seed, this->prf->get_block_size(this->prf), + bytes, out); } METHOD(tls_prf_t, destroy12, void, @@ -135,26 +142,31 @@ struct private_tls_prf10_t { prf_t *sha1; }; -METHOD(tls_prf_t, set_key10, void, +METHOD(tls_prf_t, set_key10, bool, private_tls_prf10_t *this, chunk_t key) { size_t len = key.len / 2 + key.len % 2; - this->md5->set_key(this->md5, chunk_create(key.ptr, len)); - this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, len)); + return this->md5->set_key(this->md5, chunk_create(key.ptr, len)) && + this->sha1->set_key(this->sha1, chunk_create(key.ptr + key.len - len, + len)); } -METHOD(tls_prf_t, get_bytes10, void, +METHOD(tls_prf_t, get_bytes10, bool, private_tls_prf10_t *this, char *label, chunk_t seed, size_t bytes, char *out) { char buf[bytes]; - p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5), - bytes, out); - p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1), - bytes, buf); + if (!p_hash(this->md5, label, seed, this->md5->get_block_size(this->md5), + bytes, out) || + !p_hash(this->sha1, label, seed, this->sha1->get_block_size(this->sha1), + bytes, buf)) + { + return FALSE; + } memxor(out, buf, bytes); + return TRUE; } METHOD(tls_prf_t, destroy10, void, diff --git a/src/libtls/tls_prf.h b/src/libtls/tls_prf.h index 9fb9bc2de..095eaea3a 100644 --- a/src/libtls/tls_prf.h +++ b/src/libtls/tls_prf.h @@ -34,8 +34,9 @@ struct tls_prf_t { * Set the key of the PRF function. * * @param key key to set + * @return TRUE if key set successfully */ - void (*set_key)(tls_prf_t *this, chunk_t key); + bool (*set_key)(tls_prf_t *this, chunk_t key); /** * Generate a series of bytes using a label and a seed. @@ -44,8 +45,9 @@ struct tls_prf_t { * @param seed seed input value * @param bytes number of bytes to get * @param out buffer receiving bytes + * @return TRUE if bytes generated successfully */ - void (*get_bytes)(tls_prf_t *this, char *label, chunk_t seed, + bool (*get_bytes)(tls_prf_t *this, char *label, chunk_t seed, size_t bytes, char *out); /** diff --git a/src/libtls/tls_protection.c b/src/libtls/tls_protection.c index dc734545c..8263728bb 100644 --- a/src/libtls/tls_protection.c +++ b/src/libtls/tls_protection.c @@ -93,7 +93,7 @@ struct private_tls_protection_t { /** * Create the header and feed it into a signer for MAC verification */ -static void sigheader(signer_t *signer, u_int32_t seq, u_int8_t type, +static bool sigheader(signer_t *signer, u_int32_t seq, u_int8_t type, u_int16_t version, u_int16_t length) { /* we only support 32 bit sequence numbers, but TLS uses 64 bit */ @@ -110,7 +110,7 @@ static void sigheader(signer_t *signer, u_int32_t seq, u_int8_t type, htoun16(&header.version, version); htoun16(&header.length, length); - signer->get_signature(signer, chunk_from_thing(header), NULL); + return signer->get_signature(signer, chunk_from_thing(header), NULL); } METHOD(tls_protection_t, process, status_t, @@ -150,7 +150,12 @@ METHOD(tls_protection_t, process, status_t, return NEED_MORE; } } - this->crypter_in->decrypt(this->crypter_in, data, iv, NULL); + if (!this->crypter_in->decrypt(this->crypter_in, data, iv, NULL)) + { + free(next_iv.ptr); + this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC); + return NEED_MORE; + } if (next_iv.len) { /* next record IV is last ciphertext block of this record */ @@ -180,8 +185,9 @@ METHOD(tls_protection_t, process, status_t, mac = chunk_skip(data, data.len - bs); data.len -= bs; - sigheader(this->signer_in, this->seq_in, type, this->version, data.len); - if (!this->signer_in->verify_signature(this->signer_in, data, mac)) + if (!sigheader(this->signer_in, this->seq_in, type, + this->version, data.len) || + !this->signer_in->verify_signature(this->signer_in, data, mac)) { DBG1(DBG_TLS, "TLS record MAC verification failed"); this->alert->add(this->alert, TLS_FATAL, TLS_BAD_RECORD_MAC); @@ -218,9 +224,13 @@ METHOD(tls_protection_t, build, status_t, { chunk_t mac; - sigheader(this->signer_out, this->seq_out, *type, - this->version, data->len); - this->signer_out->allocate_signature(this->signer_out, *data, &mac); + if (!sigheader(this->signer_out, this->seq_out, *type, + this->version, data->len) || + !this->signer_out->allocate_signature(this->signer_out, + *data, &mac)) + { + return FAILED; + } if (this->crypter_out) { chunk_t padding, iv; @@ -238,20 +248,29 @@ METHOD(tls_protection_t, build, status_t, } else { /* TLSv1.1 uses random IVs, prepended to record */ - if (!this->rng) + iv.len = this->crypter_out->get_iv_size(this->crypter_out); + if (!this->rng || + !this->rng->allocate_bytes(this->rng, iv.len, &iv)) { - DBG1(DBG_TLS, "no RNG supported to generate TLS IV"); + DBG1(DBG_TLS, "failed to generate TLS IV"); free(data->ptr); return FAILED; } - iv.len = this->crypter_out->get_iv_size(this->crypter_out); - this->rng->allocate_bytes(this->rng, iv.len, &iv); } *data = chunk_cat("mmcc", *data, mac, padding, chunk_from_thing(padding_length)); /* encrypt inline */ - this->crypter_out->encrypt(this->crypter_out, *data, iv, NULL); + if (!this->crypter_out->encrypt(this->crypter_out, *data, + iv, NULL)) + { + if (!this->iv_out.len) + { + free(iv.ptr); + } + free(data->ptr); + return FAILED; + } if (this->iv_out.len) { /* next record IV is last ciphertext block of this record */ diff --git a/src/libtls/tls_server.c b/src/libtls/tls_server.c index e3617dc9a..a66448d24 100644 --- a/src/libtls/tls_server.c +++ b/src/libtls/tls_server.c @@ -266,13 +266,15 @@ static status_t process_client_hello(private_tls_server_t *this, htoun32(&this->server_random, time(NULL)); rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || + !rng->get_bytes(rng, sizeof(this->server_random) - 4, + this->server_random + 4)) { - DBG1(DBG_TLS, "no suitable RNG found to generate server random"); + DBG1(DBG_TLS, "failed to generate server random"); this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + DESTROY_IF(rng); return NEED_MORE; } - rng->get_bytes(rng, sizeof(this->server_random) - 4, this->server_random + 4); rng->destroy(rng); if (!this->tls->set_version(this->tls, version)) @@ -311,11 +313,11 @@ static status_t process_client_hello(private_tls_server_t *this, return NEED_MORE; } rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - if (rng) + if (!rng || !rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session)) { - rng->allocate_bytes(rng, SESSION_ID_SIZE, &this->session); - rng->destroy(rng); + DBG1(DBG_TLS, "generating TLS session identifier failed, skipped"); } + DESTROY_IF(rng); DBG1(DBG_TLS, "negotiated %N using suite %N", tls_version_names, this->tls->get_version(this->tls), tls_cipher_suite_names, this->suite); @@ -407,13 +409,13 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this, htoun16(premaster, this->client_version); /* pre-randomize premaster for failure cases */ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!rng || !rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2)) { - DBG1(DBG_TLS, "creating RNG failed"); + DBG1(DBG_TLS, "failed to generate premaster secret"); this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + DESTROY_IF(rng); return NEED_MORE; } - rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2); rng->destroy(rng); if (this->private && @@ -436,10 +438,14 @@ static status_t process_key_exchange_encrypted(private_tls_server_t *this, DBG1(DBG_TLS, "decrypting Client Key Exchange failed"); } - this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), - this->session, this->peer, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + if (!this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster), + this->session, this->peer, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random))) + { + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + return NEED_MORE; + } this->state = STATE_KEY_EXCHANGE_RECEIVED; return NEED_MORE; @@ -485,10 +491,15 @@ static status_t process_key_exchange_dhe(private_tls_server_t *this, return NEED_MORE; } - this->crypto->derive_secrets(this->crypto, premaster, - this->session, this->peer, - chunk_from_thing(this->client_random), - chunk_from_thing(this->server_random)); + if (!this->crypto->derive_secrets(this->crypto, premaster, + this->session, this->peer, + chunk_from_thing(this->client_random), + chunk_from_thing(this->server_random))) + { + this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR); + chunk_clear(&premaster); + return NEED_MORE; + } chunk_clear(&premaster); this->state = STATE_KEY_EXCHANGE_RECEIVED; diff --git a/src/libtnccs/Makefile.in b/src/libtnccs/Makefile.in index 61a51fb4c..5eac73ab0 100644 --- a/src/libtnccs/Makefile.in +++ b/src/libtnccs/Makefile.in @@ -49,6 +49,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; @@ -78,7 +79,7 @@ libtnccs_la_DEPENDENCIES = $(top_builddir)/src/libtncif/libtncif.la am_libtnccs_la_OBJECTS = tnc.lo imv_recommendations.lo tnccs.lo \ tnccs_manager.lo libtnccs_la_OBJECTS = $(am_libtnccs_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -104,6 +105,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -198,11 +200,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -219,11 +224,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -239,6 +245,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -248,7 +255,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/libtnccs/tnc/imv/imv_recommendations.h b/src/libtnccs/tnc/imv/imv_recommendations.h index d694e16ae..e7fe355f7 100644 --- a/src/libtnccs/tnc/imv/imv_recommendations.h +++ b/src/libtnccs/tnc/imv/imv_recommendations.h @@ -67,6 +67,11 @@ struct recommendations_t { TNC_IMV_Action_Recommendation *rec, TNC_IMV_Evaluation_Result *eval); + /** + * Clear all recommendation information + */ + void (*clear_recommendation)(recommendations_t *this); + /** * Get the preferred language for remediation messages * @@ -109,11 +114,6 @@ struct recommendations_t { */ enumerator_t* (*create_reason_enumerator)(recommendations_t *this); - /** - * Clears all reason entries - */ - void (*clear_reasons)(recommendations_t *this); - /** * Destroys an imv_t object. */ diff --git a/src/libtnccs/tnc/tnc.c b/src/libtnccs/tnc/tnc.c index 652afc291..7c0ee4132 100644 --- a/src/libtnccs/tnc/tnc.c +++ b/src/libtnccs/tnc/tnc.c @@ -57,7 +57,7 @@ void libtnccs_init(void) INIT(this, .public = { }, - ); + ); tnc = &this->public; } @@ -75,6 +75,7 @@ void libtnccs_deinit(void) static bool load_imcvs_from_config(char *filename, bool is_imc) { + bool success = FALSE; int fd, line_nr = 0; chunk_t src, line; struct stat sb; @@ -110,7 +111,6 @@ static bool load_imcvs_from_config(char *filename, bool is_imc) while (fetchline(&src, &line)) { char *name, *path; - bool success; chunk_t token; line_nr++; @@ -126,7 +126,7 @@ static bool load_imcvs_from_config(char *filename, bool is_imc) { DBG1(DBG_TNC, "line %d: keyword must be followed by a space", line_nr); - return FALSE; + break; } /* only interested in IMCs or IMVs depending on label */ @@ -141,7 +141,7 @@ static bool load_imcvs_from_config(char *filename, bool is_imc) { DBG1(DBG_TNC, "line %d: %s name must be set in double quotes", line_nr, label); - return FALSE; + break; } /* copy the IMC/IMV name */ @@ -154,7 +154,7 @@ static bool load_imcvs_from_config(char *filename, bool is_imc) { DBG1(DBG_TNC, "line %d: %s path is missing", line_nr, label); free(name); - return FALSE; + break; } if (!extract_token(&token, ' ', &line)) { @@ -177,12 +177,12 @@ static bool load_imcvs_from_config(char *filename, bool is_imc) } if (!success) { - return FALSE; + break; } } munmap(addr, sb.st_size); close(fd); - return TRUE; + return success; } /** diff --git a/src/libtnccs/tnc/tnccs/tnccs_manager.h b/src/libtnccs/tnc/tnccs/tnccs_manager.h index 9ca450468..cbf2dc0e9 100644 --- a/src/libtnccs/tnc/tnccs/tnccs_manager.h +++ b/src/libtnccs/tnc/tnccs/tnccs_manager.h @@ -70,6 +70,7 @@ struct tnccs_manager_t { * @param tnccs TNCCS connection instance * @param send_message TNCCS callback function * @param request_handshake_retry pointer to boolean variable + * @param max_msg_len maximum PA-TNC message size * @param recs pointer to IMV recommendation set * @return assigned connection ID */ @@ -77,6 +78,7 @@ struct tnccs_manager_t { tnccs_type_t type, tnccs_t *tnccs, tnccs_send_message_t send_message, bool *request_handshake_retry, + u_int32_t max_msg_len, recommendations_t **recs); /** diff --git a/src/libtncif/Makefile.in b/src/libtncif/Makefile.in index 462b8bd3f..013266c20 100644 --- a/src/libtncif/Makefile.in +++ b/src/libtncif/Makefile.in @@ -49,13 +49,14 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libtncif_la_LIBADD = am_libtncif_la_OBJECTS = tncif_names.lo tncif_pa_subtypes.lo libtncif_la_OBJECTS = $(am_libtncif_la_OBJECTS) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -81,6 +82,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -175,11 +177,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -196,11 +201,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -216,6 +222,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -225,7 +232,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/manager/Makefile.in b/src/manager/Makefile.in index 8ae5ebf36..e65328cfa 100644 --- a/src/manager/Makefile.in +++ b/src/manager/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(managerdir)" \ @@ -72,7 +73,7 @@ am__DEPENDENCIES_1 = manager_fcgi_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libfast/libfast.la $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -125,6 +126,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -219,11 +221,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -240,11 +245,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -260,6 +266,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -269,7 +276,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/manager/storage.c b/src/manager/storage.c index 5461a4288..6a8e76e5e 100644 --- a/src/manager/storage.c +++ b/src/manager/storage.c @@ -58,7 +58,11 @@ METHOD(storage_t, login, int, data = chunk_alloca(username_len + password_len); memcpy(data.ptr, username, username_len); memcpy(data.ptr + username_len, password, password_len); - hasher->get_hash(hasher, data, hash.ptr); + if (!hasher->get_hash(hasher, data, hash.ptr)) + { + hasher->destroy(hasher); + return 0; + } hasher->destroy(hasher); hex_str = chunk_to_hex(hash, NULL, FALSE); diff --git a/src/medsrv/Makefile.in b/src/medsrv/Makefile.in index 95f02c580..85b1f0d92 100644 --- a/src/medsrv/Makefile.in +++ b/src/medsrv/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(medsrvdir)" \ @@ -66,7 +67,7 @@ medsrv_fcgi_OBJECTS = $(am_medsrv_fcgi_OBJECTS) medsrv_fcgi_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la \ $(top_builddir)/src/libfast/libfast.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -115,6 +116,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -209,11 +211,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -230,11 +235,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -250,6 +256,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -259,7 +266,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/medsrv/controller/peer_controller.c b/src/medsrv/controller/peer_controller.c old mode 100755 new mode 100644 diff --git a/src/medsrv/controller/peer_controller.h b/src/medsrv/controller/peer_controller.h old mode 100755 new mode 100644 diff --git a/src/medsrv/controller/user_controller.c b/src/medsrv/controller/user_controller.c old mode 100755 new mode 100644 index 12bd938fe..35c9d90c8 --- a/src/medsrv/controller/user_controller.c +++ b/src/medsrv/controller/user_controller.c @@ -64,7 +64,11 @@ static chunk_t hash_password(char *login, char *password) } data = chunk_cata("cc", chunk_create(login, strlen(login)), chunk_create(password, strlen(password))); - hasher->allocate_hash(hasher, data, &hash); + if (!hasher->allocate_hash(hasher, data, &hash)) + { + hasher->destroy(hasher); + return chunk_empty; + } hasher->destroy(hasher); return hash; } diff --git a/src/medsrv/controller/user_controller.h b/src/medsrv/controller/user_controller.h old mode 100755 new mode 100644 diff --git a/src/medsrv/filter/auth_filter.c b/src/medsrv/filter/auth_filter.c old mode 100755 new mode 100644 diff --git a/src/medsrv/filter/auth_filter.h b/src/medsrv/filter/auth_filter.h old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/footer.cs b/src/medsrv/templates/footer.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/header.cs b/src/medsrv/templates/header.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/peer/add.cs b/src/medsrv/templates/peer/add.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/peer/edit.cs b/src/medsrv/templates/peer/edit.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/peer/list.cs b/src/medsrv/templates/peer/list.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/static/favicon.ico b/src/medsrv/templates/static/favicon.ico old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/static/strongswan.png b/src/medsrv/templates/static/strongswan.png old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/static/style.css b/src/medsrv/templates/static/style.css old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/user/add.cs b/src/medsrv/templates/user/add.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/user/edit.cs b/src/medsrv/templates/user/edit.cs old mode 100755 new mode 100644 diff --git a/src/medsrv/templates/user/login.cs b/src/medsrv/templates/user/login.cs old mode 100755 new mode 100644 diff --git a/src/openac/Makefile.in b/src/openac/Makefile.in index 95043350d..9b67a5667 100644 --- a/src/openac/Makefile.in +++ b/src/openac/Makefile.in @@ -51,6 +51,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)" @@ -59,7 +60,7 @@ am_openac_OBJECTS = openac.$(OBJEXT) openac_OBJECTS = $(am_openac_OBJECTS) openac_DEPENDENCIES = \ $(top_builddir)/src/libstrongswan/libstrongswan.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -109,6 +110,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -203,11 +205,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -224,11 +229,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -244,6 +250,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -253,7 +260,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/openac/openac.c b/src/openac/openac.c old mode 100755 new mode 100644 diff --git a/src/pki/Makefile.in b/src/pki/Makefile.in index f9c417658..609ab345b 100644 --- a/src/pki/Makefile.in +++ b/src/pki/Makefile.in @@ -50,6 +50,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(ipsecdir)" @@ -60,7 +61,7 @@ am_pki_OBJECTS = pki.$(OBJEXT) command.$(OBJEXT) gen.$(OBJEXT) \ verify.$(OBJEXT) pki_OBJECTS = $(am_pki_OBJECTS) pki_DEPENDENCIES = $(top_builddir)/src/libstrongswan/libstrongswan.la -DEFAULT_INCLUDES = -I.@am__isrc@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f @@ -86,6 +87,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BFDLIB = @BFDLIB@ BTLIB = @BTLIB@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ @@ -180,11 +182,14 @@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ c_plugins = @c_plugins@ +charon_natt_port = @charon_natt_port@ +charon_plugins = @charon_plugins@ +charon_udp_port = @charon_udp_port@ clearsilver_LIBS = @clearsilver_LIBS@ datadir = @datadir@ datarootdir = @datarootdir@ dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ +dev_headers = @dev_headers@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ @@ -201,11 +206,12 @@ imcvdir = @imcvdir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ +ipsec_script = @ipsec_script@ +ipsec_script_upper = @ipsec_script_upper@ ipsecdir = @ipsecdir@ ipsecgroup = @ipsecgroup@ ipseclibdir = @ipseclibdir@ ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ libdir = @libdir@ libexecdir = @libexecdir@ linux_headers = @linux_headers@ @@ -221,6 +227,7 @@ mkdir_p = @mkdir_p@ nm_CFLAGS = @nm_CFLAGS@ nm_LIBS = @nm_LIBS@ nm_ca_dir = @nm_ca_dir@ +nm_plugins = @nm_plugins@ oldincludedir = @oldincludedir@ openac_plugins = @openac_plugins@ p_plugins = @p_plugins@ @@ -230,7 +237,6 @@ pdfdir = @pdfdir@ piddir = @piddir@ pki_plugins = @pki_plugins@ plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ pool_plugins = @pool_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ diff --git a/src/pki/command.c b/src/pki/command.c index 07ba5bb1d..43328575c 100644 --- a/src/pki/command.c +++ b/src/pki/command.c @@ -144,7 +144,7 @@ void command_register(command_t command) /* append default options, but not to --help */ if (!active) { - for (i = 0; i < countof(cmds[registered].options); i++) + for (i = 0; i < countof(cmds[registered].options) - 1; i++) { if (cmds[registered].options[i].name) { diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 20163edf2..47e668b6c 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -105,8 +105,8 @@ static int issue() } continue; case 'g': - digest = get_digest(arg); - if (digest == HASH_UNKNOWN) + digest = enum_from_name(hash_algorithm_short_names, arg); + if (digest == -1) { error = "invalid --digest type"; goto usage; @@ -229,6 +229,10 @@ static int issue() { flags |= X509_CLIENT_AUTH; } + else if (streq(arg, "ikeIntermediate")) + { + flags |= X509_IKE_INTERMEDIATE; + } else if (streq(arg, "crlSign")) { flags |= X509_CRL_SIGN; @@ -352,11 +356,11 @@ static int issue() error = "no random number generator found"; goto end; } - rng->allocate_bytes(rng, 8, &serial); - while (*serial.ptr == 0x00) + if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE)) { - /* we don't accept a serial number with leading zeroes */ - rng->get_bytes(rng, 1, serial.ptr); + error = "failed to generate serial number"; + rng->destroy(rng); + goto end; } rng->destroy(rng); } diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c index a7f02bfac..90cf254c8 100644 --- a/src/pki/commands/print.c +++ b/src/pki/commands/print.c @@ -133,6 +133,10 @@ static void print_x509(x509_t *x509) { printf("clientAuth "); } + if (flags & X509_IKE_INTERMEDIATE) + { + printf("iKEIntermediate "); + } if (flags & X509_SELF_SIGNED) { printf("self-signed "); diff --git a/src/pki/commands/req.c b/src/pki/commands/req.c index 087a97b3e..d050c7032 100644 --- a/src/pki/commands/req.c +++ b/src/pki/commands/req.c @@ -63,8 +63,8 @@ static int req() } continue; case 'g': - digest = get_digest(arg); - if (digest == HASH_UNKNOWN) + digest = enum_from_name(hash_algorithm_short_names, arg); + if (digest == -1) { error = "invalid --digest type"; goto usage; diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index c4508a671..4a50aa463 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -94,8 +94,8 @@ static int self() } continue; case 'g': - digest = get_digest(arg); - if (digest == HASH_UNKNOWN) + digest = enum_from_name(hash_algorithm_short_names, arg); + if (digest == -1) { error = "invalid --digest type"; goto usage; @@ -212,6 +212,10 @@ static int self() { flags |= X509_CLIENT_AUTH; } + else if (streq(arg, "ikeIntermediate")) + { + flags |= X509_IKE_INTERMEDIATE; + } else if (streq(arg, "crlSign")) { flags |= X509_CRL_SIGN; @@ -294,11 +298,11 @@ static int self() error = "no random number generator found"; goto end; } - rng->allocate_bytes(rng, 8, &serial); - while (*serial.ptr == 0x00) + if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE)) { - /* we don't accept a serial number with leading zeroes */ - rng->get_bytes(rng, 1, serial.ptr); + error = "failed to generate serial number"; + rng->destroy(rng); + goto end; } rng->destroy(rng); } diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c index 153734f53..4ada120ed 100644 --- a/src/pki/commands/signcrl.c +++ b/src/pki/commands/signcrl.c @@ -141,8 +141,8 @@ static int sign_crl() case 'h': goto usage; case 'g': - digest = get_digest(arg); - if (digest == HASH_UNKNOWN) + digest = enum_from_name(hash_algorithm_short_names, arg); + if (digest == -1) { error = "invalid --digest type"; goto usage; diff --git a/src/pki/commands/verify.c b/src/pki/commands/verify.c index bbcc53891..3e983d3ec 100644 --- a/src/pki/commands/verify.c +++ b/src/pki/commands/verify.c @@ -77,7 +77,7 @@ static int verify() { ca = cert; } - if (cert->issued_by(cert, ca)) + if (cert->issued_by(cert, ca, NULL)) { if (cert->get_validity(cert, NULL, NULL, NULL)) { diff --git a/src/pki/pki.c b/src/pki/pki.c index 3005d2fcd..e28bf1595 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -79,38 +79,6 @@ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type) return FALSE; } -/** - * Convert a digest string to a hash algorithm - */ -hash_algorithm_t get_digest(char *name) -{ - if (streq(name, "md5")) - { - return HASH_MD5; - } - if (streq(name, "sha1")) - { - return HASH_SHA1; - } - if (streq(name, "sha224")) - { - return HASH_SHA224; - } - if (streq(name, "sha256")) - { - return HASH_SHA256; - } - if (streq(name, "sha384")) - { - return HASH_SHA384; - } - if (streq(name, "sha512")) - { - return HASH_SHA512; - } - return HASH_UNKNOWN; -} - /** * Callback credential set pki uses */ diff --git a/src/pki/pki.h b/src/pki/pki.h index 9c145cdc0..f72b1804c 100644 --- a/src/pki/pki.h +++ b/src/pki/pki.h @@ -31,9 +31,4 @@ */ bool get_form(char *form, cred_encoding_type_t *enc, credential_type_t type); -/** - * Convert a digest string to a hash algorithm - */ -hash_algorithm_t get_digest(char *name); - #endif /** PKI_H_ @}*/ diff --git a/src/pluto/Android.mk b/src/pluto/Android.mk deleted file mode 100644 index 618f79c42..000000000 --- a/src/pluto/Android.mk +++ /dev/null @@ -1,80 +0,0 @@ -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# copy-n-paste from Makefile.am -LOCAL_SRC_FILES := \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -LOCAL_SRC_FILES += $(call add_plugin, xauth) - -# build pluto ------------------------------------------------------------------ - -LOCAL_C_INCLUDES += \ - $(libvstr_PATH) \ - $(strongswan_PATH)/src/libhydra \ - $(strongswan_PATH)/src/libstrongswan \ - $(strongswan_PATH)/src/libfreeswan \ - $(strongswan_PATH)/src/whack - -LOCAL_CFLAGS := $(strongswan_CFLAGS) \ - -DPLUTO -DVENDORID -DXAUTH_VID -DCISCO_QUIRKS \ - -DTHREADS -DKERNEL26_HAS_KAME_DUPLICATES \ - -DPLUGINS='"$(strongswan_PLUTO_PLUGINS)"' - -LOCAL_MODULE := pluto - -LOCAL_MODULE_TAGS := optional - -LOCAL_ARM_MODE := arm - -LOCAL_PRELINK_MODULE := false - -LOCAL_SHARED_LIBRARIES += libstrongswan libhydra libfreeswan libcutils - -include $(BUILD_EXECUTABLE) diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am deleted file mode 100644 index 3fd0e039c..000000000 --- a/src/pluto/Makefile.am +++ /dev/null @@ -1,155 +0,0 @@ -# Makefile.am was ported from the old Makefile the most -# painless way. Only the most important options are included, -# further work may be necessary here... - -ipsec_PROGRAMS = pluto - -if USE_ADNS -ipsec_PROGRAMS += _pluto_adns -endif - -pluto_SOURCES = \ -ac.c ac.h \ -alg_info.c alg_info.h \ -ca.c ca.h \ -certs.c certs.h \ -connections.c connections.h \ -constants.c constants.h \ -cookie.c cookie.h \ -crl.c crl.h \ -crypto.c crypto.h \ -db_ops.c db_ops.h \ -defs.c defs.h \ -demux.c demux.h \ -event_queue.c event_queue.h \ -fetch.c fetch.h \ -foodgroups.c foodgroups.h \ -ike_alg.c ike_alg.h \ -ipsec_doi.c ipsec_doi.h \ -kameipsec.h \ -kernel.c kernel.h \ -kernel_alg.c kernel_alg.h \ -kernel_pfkey.c kernel_pfkey.h \ -keys.c keys.h \ -lex.c lex.h \ -log.c log.h \ -myid.c myid.h \ -modecfg.c modecfg.h \ -nat_traversal.c nat_traversal.h \ -ocsp.c ocsp.h \ -packet.c packet.h \ -pkcs7.c pkcs7.h \ -plugin_list.c plugin_list.h \ -pluto.c pluto.h \ -plutomain.c \ -rcv_whack.c rcv_whack.h \ -server.c server.h \ -smartcard.c smartcard.h \ -spdb.c spdb.h \ -state.c state.h \ -timer.c timer.h \ -vendor.c vendor.h \ -virtual.c virtual.h \ -whack_attribute.c whack_attribute.h \ -xauth/xauth_manager.c xauth/xauth_manager.h \ -xauth/xauth_provider.h xauth/xauth_verifier.h \ -x509.c x509.h \ -builder.c builder.h \ -rsaref/pkcs11t.h rsaref/pkcs11.h rsaref/unix.h rsaref/pkcs11f.h - -if USE_ADNS -pluto_SOURCES += \ -dnskey.c dnskey.h - -_pluto_adns_SOURCES = \ -adns.c adns.h -endif - -plutomain.o : $(top_builddir)/config.status - -LIBSTRONGSWANDIR=$(top_builddir)/src/libstrongswan -LIBFREESWANDIR=$(top_builddir)/src/libfreeswan -LIBHYDRADIR=$(top_builddir)/src/libhydra - -INCLUDES = \ --I${linux_headers} \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/whack - -AM_CFLAGS = -rdynamic \ --DIPSEC_DIR=\"${ipsecdir}\" \ --DIPSEC_CONFDIR=\"${sysconfdir}\" \ --DIPSEC_PIDDIR=\"${piddir}\" \ --DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ --DPLUGINS=\""${pluto_plugins}\"" \ --DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ --DKERNEL26_HAS_KAME_DUPLICATES \ --DPLUTO -DDEBUG - -pluto_LDADD = \ -$(LIBSTRONGSWANDIR)/libstrongswan.la \ -$(LIBFREESWANDIR)/libfreeswan.a \ -$(LIBHYDRADIR)/libhydra.la \ --lresolv $(PTHREADLIB) $(DLLIB) - -if USE_ADNS -_pluto_adns_LDADD = \ -$(LIBFREESWANDIR)/libfreeswan.a \ --lresolv $(DLLIB) -endif - -dist_man_MANS = pluto.8 - -EXTRA_DIST = Android.mk - -# compile options -################# - -# This compile option activates the sending of a strongSwan VID -if USE_VENDORID - AM_CFLAGS += -DVENDORID -endif - -# This compile option activates the sending of the XAUTH VID -if USE_XAUTH_VID - AM_CFLAGS += -DXAUTH_VID -endif - -# This compile option activates the support of the Cisco VPN client -if USE_CISCO_QUIRKS - AM_CFLAGS += -DCISCO_QUIRKS -endif - -# This compile option activates NAT traversal with IPSec transport mode -if USE_NAT_TRANSPORT - AM_CFLAGS += -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT -endif - -# This compile option activates smartcard support -if USE_SMARTCARD - AM_CFLAGS += -DSMARTCARD -endif - -if USE_LIBCAP - pluto_LDADD += -lcap -endif - -if USE_THREADS - AM_CFLAGS += -DTHREADS -endif - -if USE_ADNS - AM_CFLAGS += -DADNS -endif - -# build optional plugins -######################## - -SUBDIRS = . - -if USE_XAUTH - SUBDIRS += plugins/xauth -endif - diff --git a/src/pluto/Makefile.in b/src/pluto/Makefile.in deleted file mode 100644 index b055ba289..000000000 --- a/src/pluto/Makefile.in +++ /dev/null @@ -1,1001 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile.am was ported from the old Makefile the most -# painless way. Only the most important options are included, -# further work may be necessary here... - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -ipsec_PROGRAMS = pluto$(EXEEXT) $(am__EXEEXT_1) -@USE_ADNS_TRUE@am__append_1 = _pluto_adns -@USE_ADNS_TRUE@am__append_2 = \ -@USE_ADNS_TRUE@dnskey.c dnskey.h - - -# compile options -################# - -# This compile option activates the sending of a strongSwan VID -@USE_VENDORID_TRUE@am__append_3 = -DVENDORID - -# This compile option activates the sending of the XAUTH VID -@USE_XAUTH_VID_TRUE@am__append_4 = -DXAUTH_VID - -# This compile option activates the support of the Cisco VPN client -@USE_CISCO_QUIRKS_TRUE@am__append_5 = -DCISCO_QUIRKS - -# This compile option activates NAT traversal with IPSec transport mode -@USE_NAT_TRANSPORT_TRUE@am__append_6 = -DI_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT - -# This compile option activates smartcard support -@USE_SMARTCARD_TRUE@am__append_7 = -DSMARTCARD -@USE_LIBCAP_TRUE@am__append_8 = -lcap -@USE_THREADS_TRUE@am__append_9 = -DTHREADS -@USE_ADNS_TRUE@am__append_10 = -DADNS -@USE_XAUTH_TRUE@am__append_11 = plugins/xauth -subdir = src/pluto -DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -@USE_ADNS_TRUE@am__EXEEXT_1 = _pluto_adns$(EXEEXT) -am__installdirs = "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)" -PROGRAMS = $(ipsec_PROGRAMS) -am___pluto_adns_SOURCES_DIST = adns.c adns.h -@USE_ADNS_TRUE@am__pluto_adns_OBJECTS = adns.$(OBJEXT) -_pluto_adns_OBJECTS = $(am__pluto_adns_OBJECTS) -am__DEPENDENCIES_1 = -@USE_ADNS_TRUE@_pluto_adns_DEPENDENCIES = \ -@USE_ADNS_TRUE@ $(LIBFREESWANDIR)/libfreeswan.a \ -@USE_ADNS_TRUE@ $(am__DEPENDENCIES_1) -am__pluto_SOURCES_DIST = ac.c ac.h alg_info.c alg_info.h ca.c ca.h \ - certs.c certs.h connections.c connections.h constants.c \ - constants.h cookie.c cookie.h crl.c crl.h crypto.c crypto.h \ - db_ops.c db_ops.h defs.c defs.h demux.c demux.h event_queue.c \ - event_queue.h fetch.c fetch.h foodgroups.c foodgroups.h \ - ike_alg.c ike_alg.h ipsec_doi.c ipsec_doi.h kameipsec.h \ - kernel.c kernel.h kernel_alg.c kernel_alg.h kernel_pfkey.c \ - kernel_pfkey.h keys.c keys.h lex.c lex.h log.c log.h myid.c \ - myid.h modecfg.c modecfg.h nat_traversal.c nat_traversal.h \ - ocsp.c ocsp.h packet.c packet.h pkcs7.c pkcs7.h plugin_list.c \ - plugin_list.h pluto.c pluto.h plutomain.c rcv_whack.c \ - rcv_whack.h server.c server.h smartcard.c smartcard.h spdb.c \ - spdb.h state.c state.h timer.c timer.h vendor.c vendor.h \ - virtual.c virtual.h whack_attribute.c whack_attribute.h \ - xauth/xauth_manager.c xauth/xauth_manager.h \ - xauth/xauth_provider.h xauth/xauth_verifier.h x509.c x509.h \ - builder.c builder.h rsaref/pkcs11t.h rsaref/pkcs11.h \ - rsaref/unix.h rsaref/pkcs11f.h dnskey.c dnskey.h -@USE_ADNS_TRUE@am__objects_1 = dnskey.$(OBJEXT) -am_pluto_OBJECTS = ac.$(OBJEXT) alg_info.$(OBJEXT) ca.$(OBJEXT) \ - certs.$(OBJEXT) connections.$(OBJEXT) constants.$(OBJEXT) \ - cookie.$(OBJEXT) crl.$(OBJEXT) crypto.$(OBJEXT) \ - db_ops.$(OBJEXT) defs.$(OBJEXT) demux.$(OBJEXT) \ - event_queue.$(OBJEXT) fetch.$(OBJEXT) foodgroups.$(OBJEXT) \ - ike_alg.$(OBJEXT) ipsec_doi.$(OBJEXT) kernel.$(OBJEXT) \ - kernel_alg.$(OBJEXT) kernel_pfkey.$(OBJEXT) keys.$(OBJEXT) \ - lex.$(OBJEXT) log.$(OBJEXT) myid.$(OBJEXT) modecfg.$(OBJEXT) \ - nat_traversal.$(OBJEXT) ocsp.$(OBJEXT) packet.$(OBJEXT) \ - pkcs7.$(OBJEXT) plugin_list.$(OBJEXT) pluto.$(OBJEXT) \ - plutomain.$(OBJEXT) rcv_whack.$(OBJEXT) server.$(OBJEXT) \ - smartcard.$(OBJEXT) spdb.$(OBJEXT) state.$(OBJEXT) \ - timer.$(OBJEXT) vendor.$(OBJEXT) virtual.$(OBJEXT) \ - whack_attribute.$(OBJEXT) xauth_manager.$(OBJEXT) \ - x509.$(OBJEXT) builder.$(OBJEXT) $(am__objects_1) -pluto_OBJECTS = $(am_pluto_OBJECTS) -pluto_DEPENDENCIES = $(LIBSTRONGSWANDIR)/libstrongswan.la \ - $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(_pluto_adns_SOURCES) $(pluto_SOURCES) -DIST_SOURCES = $(am___pluto_adns_SOURCES_DIST) \ - $(am__pluto_SOURCES_DIST) -RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ - html-recursive info-recursive install-data-recursive \ - install-dvi-recursive install-exec-recursive \ - install-html-recursive install-info-recursive \ - install-pdf-recursive install-ps-recursive install-recursive \ - installcheck-recursive installdirs-recursive pdf-recursive \ - ps-recursive uninstall-recursive -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -man8dir = $(mandir)/man8 -NROFF = nroff -MANS = $(dist_man_MANS) -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ - $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ - distdir -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = . plugins/xauth -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -pluto_SOURCES = ac.c ac.h alg_info.c alg_info.h ca.c ca.h certs.c \ - certs.h connections.c connections.h constants.c constants.h \ - cookie.c cookie.h crl.c crl.h crypto.c crypto.h db_ops.c \ - db_ops.h defs.c defs.h demux.c demux.h event_queue.c \ - event_queue.h fetch.c fetch.h foodgroups.c foodgroups.h \ - ike_alg.c ike_alg.h ipsec_doi.c ipsec_doi.h kameipsec.h \ - kernel.c kernel.h kernel_alg.c kernel_alg.h kernel_pfkey.c \ - kernel_pfkey.h keys.c keys.h lex.c lex.h log.c log.h myid.c \ - myid.h modecfg.c modecfg.h nat_traversal.c nat_traversal.h \ - ocsp.c ocsp.h packet.c packet.h pkcs7.c pkcs7.h plugin_list.c \ - plugin_list.h pluto.c pluto.h plutomain.c rcv_whack.c \ - rcv_whack.h server.c server.h smartcard.c smartcard.h spdb.c \ - spdb.h state.c state.h timer.c timer.h vendor.c vendor.h \ - virtual.c virtual.h whack_attribute.c whack_attribute.h \ - xauth/xauth_manager.c xauth/xauth_manager.h \ - xauth/xauth_provider.h xauth/xauth_verifier.h x509.c x509.h \ - builder.c builder.h rsaref/pkcs11t.h rsaref/pkcs11.h \ - rsaref/unix.h rsaref/pkcs11f.h $(am__append_2) -@USE_ADNS_TRUE@_pluto_adns_SOURCES = \ -@USE_ADNS_TRUE@adns.c adns.h - -LIBSTRONGSWANDIR = $(top_builddir)/src/libstrongswan -LIBFREESWANDIR = $(top_builddir)/src/libfreeswan -LIBHYDRADIR = $(top_builddir)/src/libhydra -INCLUDES = \ --I${linux_headers} \ --I$(top_srcdir)/src/libstrongswan \ --I$(top_srcdir)/src/libfreeswan \ --I$(top_srcdir)/src/libhydra \ --I$(top_srcdir)/src/whack - -AM_CFLAGS = -rdynamic -DIPSEC_DIR=\"${ipsecdir}\" \ - -DIPSEC_CONFDIR=\"${sysconfdir}\" -DIPSEC_PIDDIR=\"${piddir}\" \ - -DSHARED_SECRETS_FILE=\"${sysconfdir}/ipsec.secrets\" \ - -DPLUGINS=\""${pluto_plugins}\"" \ - -DPKCS11_DEFAULT_LIB=\"${default_pkcs11}\" \ - -DKERNEL26_HAS_KAME_DUPLICATES -DPLUTO -DDEBUG $(am__append_3) \ - $(am__append_4) $(am__append_5) $(am__append_6) \ - $(am__append_7) $(am__append_9) $(am__append_10) -pluto_LDADD = $(LIBSTRONGSWANDIR)/libstrongswan.la \ - $(LIBFREESWANDIR)/libfreeswan.a $(LIBHYDRADIR)/libhydra.la \ - -lresolv $(PTHREADLIB) $(DLLIB) $(am__append_8) -@USE_ADNS_TRUE@_pluto_adns_LDADD = \ -@USE_ADNS_TRUE@$(LIBFREESWANDIR)/libfreeswan.a \ -@USE_ADNS_TRUE@-lresolv $(DLLIB) - -dist_man_MANS = pluto.8 -EXTRA_DIST = Android.mk - -# build optional plugins -######################## -SUBDIRS = . $(am__append_11) -all: all-recursive - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/pluto/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-ipsecPROGRAMS: $(ipsec_PROGRAMS) - @$(NORMAL_INSTALL) - test -z "$(ipsecdir)" || $(MKDIR_P) "$(DESTDIR)$(ipsecdir)" - @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ - for p in $$list; do echo "$$p $$p"; done | \ - sed 's/$(EXEEXT)$$//' | \ - while read p p1; do if test -f $$p || test -f $$p1; \ - then echo "$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ - -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ - sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) files[d] = files[d] " " $$1; \ - else { print "f", $$3 "/" $$4, $$1; } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(ipsecdir)$$dir'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(ipsecdir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-ipsecPROGRAMS: - @$(NORMAL_UNINSTALL) - @list='$(ipsec_PROGRAMS)'; test -n "$(ipsecdir)" || list=; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ - -e 's/$$/$(EXEEXT)/' `; \ - test -n "$$list" || exit 0; \ - echo " ( cd '$(DESTDIR)$(ipsecdir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(ipsecdir)" && rm -f $$files - -clean-ipsecPROGRAMS: - @list='$(ipsec_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -_pluto_adns$(EXEEXT): $(_pluto_adns_OBJECTS) $(_pluto_adns_DEPENDENCIES) - @rm -f _pluto_adns$(EXEEXT) - $(LINK) $(_pluto_adns_OBJECTS) $(_pluto_adns_LDADD) $(LIBS) -pluto$(EXEEXT): $(pluto_OBJECTS) $(pluto_DEPENDENCIES) - @rm -f pluto$(EXEEXT) - $(LINK) $(pluto_OBJECTS) $(pluto_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adns.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alg_info.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/builder.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ca.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connections.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constants.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cookie.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/db_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/demux.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnskey.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fetch.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/foodgroups.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipsec_doi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_alg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_pfkey.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lex.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modecfg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myid.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nat_traversal.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ocsp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs7.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_list.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pluto.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plutomain.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcv_whack.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smartcard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spdb.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/state.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vendor.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/virtual.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/whack_attribute.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_manager.Po@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -xauth_manager.o: xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_manager.o -MD -MP -MF $(DEPDIR)/xauth_manager.Tpo -c -o xauth_manager.o `test -f 'xauth/xauth_manager.c' || echo '$(srcdir)/'`xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_manager.Tpo $(DEPDIR)/xauth_manager.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xauth/xauth_manager.c' object='xauth_manager.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_manager.o `test -f 'xauth/xauth_manager.c' || echo '$(srcdir)/'`xauth/xauth_manager.c - -xauth_manager.obj: xauth/xauth_manager.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT xauth_manager.obj -MD -MP -MF $(DEPDIR)/xauth_manager.Tpo -c -o xauth_manager.obj `if test -f 'xauth/xauth_manager.c'; then $(CYGPATH_W) 'xauth/xauth_manager.c'; else $(CYGPATH_W) '$(srcdir)/xauth/xauth_manager.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/xauth_manager.Tpo $(DEPDIR)/xauth_manager.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='xauth/xauth_manager.c' object='xauth_manager.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o xauth_manager.obj `if test -f 'xauth/xauth_manager.c'; then $(CYGPATH_W) 'xauth/xauth_manager.c'; else $(CYGPATH_W) '$(srcdir)/xauth/xauth_manager.c'; fi` - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-man8: $(dist_man_MANS) - @$(NORMAL_INSTALL) - test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" - @list=''; test -n "$(man8dir)" || exit 0; \ - { for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.8[a-z]*$$/p'; \ - } | while read p; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; echo "$$p"; \ - done | \ - sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ - sed 'N;N;s,\n, ,g' | { \ - list=; while read file base inst; do \ - if test "$$base" = "$$inst"; then list="$$list $$file"; else \ - echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ - $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ - fi; \ - done; \ - for i in $$list; do echo "$$i"; done | $(am__base_list) | \ - while read files; do \ - test -z "$$files" || { \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ - done; } - -uninstall-man8: - @$(NORMAL_UNINSTALL) - @list=''; test -n "$(man8dir)" || exit 0; \ - files=`{ for i in $$list; do echo "$$i"; done; \ - l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \ - sed -n '/\.8[a-z]*$$/p'; \ - } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ - -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ - test -z "$$files" || { \ - echo " ( cd '$(DESTDIR)$(man8dir)' && rm -f" $$files ")"; \ - cd "$(DESTDIR)$(man8dir)" && rm -f $$files; } - -# This directory's subdirectories are mostly independent; you can cd -# into them and run `make' without going through this Makefile. -# To change the values of `make' variables: instead of editing Makefiles, -# (1) if the variable is set in `config.status', edit `config.status' -# (which will cause the Makefiles to be regenerated when you run `make'); -# (2) otherwise, pass the desired values on the `make' command line. -$(RECURSIVE_TARGETS): - @fail= failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -$(RECURSIVE_CLEAN_TARGETS): - @fail= failcom='exit 1'; \ - for f in x $$MAKEFLAGS; do \ - case $$f in \ - *=* | --[!k]*);; \ - *k*) failcom='fail=yes';; \ - esac; \ - done; \ - dot_seen=no; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - rev=''; for subdir in $$list; do \ - if test "$$subdir" = "."; then :; else \ - rev="$$subdir $$rev"; \ - fi; \ - done; \ - rev="$$rev ."; \ - target=`echo $@ | sed s/-recursive//`; \ - for subdir in $$rev; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done && test -z "$$fail" -tags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ - done -ctags-recursive: - list='$(SUBDIRS)'; for subdir in $$list; do \ - test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ - done - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @list='$(MANS)'; if test -n "$$list"; then \ - list=`for p in $$list; do \ - if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ - if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ - if test -n "$$list" && \ - grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ - echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ - grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ - echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ - echo " typically \`make maintainer-clean' will remove them" >&2; \ - exit 1; \ - else :; fi; \ - else :; fi - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-recursive -all-am: Makefile $(PROGRAMS) $(MANS) -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(ipsecdir)" "$(DESTDIR)$(man8dir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-ipsecPROGRAMS clean-libtool \ - mostlyclean-am - -distclean: distclean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-ipsecPROGRAMS install-man - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: install-man8 - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-ipsecPROGRAMS uninstall-man - -uninstall-man: uninstall-man8 - -.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ - install-am install-strip tags-recursive - -.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ - all all-am check check-am clean clean-generic \ - clean-ipsecPROGRAMS clean-libtool ctags ctags-recursive \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-ipsecPROGRAMS install-man install-man8 \ - install-pdf install-pdf-am install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ - uninstall uninstall-am uninstall-ipsecPROGRAMS uninstall-man \ - uninstall-man8 - - -plutomain.o : $(top_builddir)/config.status - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/pluto/ac.c b/src/pluto/ac.c deleted file mode 100644 index cd8007aea..000000000 --- a/src/pluto/ac.c +++ /dev/null @@ -1,298 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include -#include -#include - -#include "ac.h" -#include "ca.h" -#include "certs.h" -#include "fetch.h" -#include "log.h" - -/** - * Chained list of X.509 attribute certificates - */ -static linked_list_t *acerts = NULL; - -/** - * Initialize the linked list of attribute certificates - */ -void ac_initialize(void) -{ - acerts = linked_list_create(); -} - -/** - * Free the linked list of attribute certificates - */ -void ac_finalize(void) -{ - if (acerts) - { - acerts->destroy_offset(acerts, offsetof(certificate_t, destroy)); - } -} - -/** - * Get a X.509 attribute certificate for a given holder - */ -certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial) -{ - enumerator_t *enumerator; - certificate_t *cert, *found = NULL; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - - if (issuer->equals(issuer, ac->get_holderIssuer(ac)) && - chunk_equals(serial, ac->get_holderSerial(ac))) - { - found = cert; - break; - } - } - enumerator->destroy(enumerator); - return found; -} - -/** - * Verifies a X.509 attribute certificate - */ -bool ac_verify_cert(certificate_t *cert, bool strict) -{ - ac_t *ac = (ac_t*)cert; - identification_t *subject = cert->get_subject(cert); - identification_t *issuer = cert->get_issuer(cert); - chunk_t authKeyID = ac->get_authKeyIdentifier(ac); - cert_t *aacert; - time_t notBefore, valid_until; - - DBG1(DBG_LIB, "holder: '%Y'", subject); - DBG1(DBG_LIB, "issuer: '%Y'", issuer); - - if (!cert->get_validity(cert, NULL, NULL, &valid_until)) - { - DBG1(DBG_LIB, "attribute certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, &valid_until, FALSE); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate is valid until %T", &valid_until, - FALSE); - - lock_authcert_list("verify_x509acert"); - aacert = get_authcert(issuer, authKeyID, X509_AA); - unlock_authcert_list("verify_x509acert"); - - if (aacert == NULL) - { - DBG1(DBG_LIB, "issuer aacert not found"); - return FALSE; - } - DBG2(DBG_LIB, "issuer aacert found"); - - if (!cert->issued_by(cert, aacert->cert)) - { - DBG1(DBG_LIB, "attribute certificate signature is invalid"); - return FALSE; - } - DBG1(DBG_LIB, "attribute certificate signature is valid"); - - return verify_x509cert(aacert, strict, &valid_until); -} - -/** - * Add a X.509 attribute certificate to the chained list - */ -static void ac_add_cert(certificate_t *cert) -{ - ac_t *ac = (ac_t*)cert; - identification_t *hIssuer = ac->get_holderIssuer(ac); - chunk_t hSerial = ac->get_holderSerial(ac); - - enumerator_t *enumerator; - certificate_t *cert_old; - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert_old)) - { - ac_t *ac_old = (ac_t*)cert_old; - - if (hIssuer->equals(hIssuer, ac_old->get_holderIssuer(ac_old)) && - chunk_equals(hSerial, ac_old->get_holderSerial(ac_old))) - { - if (certificate_is_newer(cert, cert_old)) - { - acerts->remove_at(acerts, enumerator); - cert_old->destroy(cert_old); - } - else - { - cert->destroy(cert); - cert = NULL; - } - break; - } - } - enumerator->destroy(enumerator); - - if (cert) - { - acerts->insert_last(acerts, cert); - } -} - -/** - * Check if at least one peer attribute matches a connection attribute - */ -bool match_group_membership(ietf_attributes_t *peer_attributes, char *conn, - ietf_attributes_t *conn_attributes) -{ - bool match; - - if (conn_attributes == NULL) - { - return TRUE; - } - - match = conn_attributes->matches(conn_attributes, peer_attributes); - DBG1(DBG_LIB, "%s: peer with attributes '%s' is %sa member of the " - "groups '%s'", conn, peer_attributes->get_string(peer_attributes), - match ? "" : "not ", conn_attributes->get_string(conn_attributes)); - - return match; -} - -/** - * Loads X.509 attribute certificates - */ -void ac_load_certs(void) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading attribute certificates from '%s'", A_CERT_PATH); - - enumerator = enumerator_create_directory(A_CERT_PATH); - if (!enumerator) - { - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - certificate_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, - BUILD_FROM_FILE, file, BUILD_END); - if (cert) - { - DBG1(DBG_LIB, " loaded attribute certificate from '%s'", file); - ac_add_cert(cert); - } - } - enumerator->destroy(enumerator); -} - -/** - * List all X.509 attribute certificates in the chained list - */ -void ac_list_certs(bool utc) -{ - enumerator_t *enumerator; - certificate_t *cert; - time_t now; - - /* determine the current time */ - time(&now); - - if (acerts->get_count(acerts) > 0) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 Attribute Certificates:"); - } - - enumerator = acerts->create_enumerator(acerts); - while (enumerator->enumerate(enumerator, &cert)) - { - ac_t *ac = (ac_t*)cert; - identification_t *entityName, *holderIssuer, *issuer; - chunk_t holderSerial, serial, authKeyID; - time_t notBefore, notAfter; - ietf_attributes_t *groups; - - whack_log(RC_COMMENT, " "); - - entityName = cert->get_subject(cert); - if (entityName) - { - whack_log(RC_COMMENT, " holder: \"%Y\"", entityName); - } - - holderIssuer = ac->get_holderIssuer(ac); - if (holderIssuer) - { - whack_log(RC_COMMENT, " hissuer: \"%Y\"", holderIssuer); - } - - holderSerial = chunk_skip_zero(ac->get_holderSerial(ac)); - if (holderSerial.ptr) - { - whack_log(RC_COMMENT, " hserial: %#B", &holderSerial); - } - - groups = ac->get_groups(ac); - if (groups) - { - whack_log(RC_COMMENT, " groups: %s", groups->get_string(groups)); - groups->destroy(groups); - } - - issuer = cert->get_issuer(cert); - whack_log(RC_COMMENT, " issuer: \"%Y\"", issuer); - - serial = chunk_skip_zero(ac->get_serial(ac)); - whack_log(RC_COMMENT, " serial: %#B", &serial); - - cert->get_validity(cert, &now, ¬Before, ¬After); - whack_log(RC_COMMENT, " validity: not before %T %s", - ¬Before, utc, - (notBefore < now)?"ok":"fatal (not valid yet)"); - whack_log(RC_COMMENT, " not after %T %s", ¬After, utc, - check_expiry(notAfter, ACERT_WARNING_INTERVAL, TRUE)); - - authKeyID = ac->get_authKeyIdentifier(ac); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - } - enumerator->destroy(enumerator); -} - diff --git a/src/pluto/ac.h b/src/pluto/ac.h deleted file mode 100644 index d4e0c1590..000000000 --- a/src/pluto/ac.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Support of X.509 attribute certificates - * Copyright (C) 2002 Ueli Galizzi, Ariane Seiler - * Copyright (C) 2003 Martin Berner, Lukas Suter - * Copyright (C) 2009 Andreas Steffen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _AC_H -#define _AC_H - -#include -#include -#include - -/* access structure for an X.509 attribute certificate */ - -extern void ac_initialize(void); -extern void ac_finalize(void); -extern void ac_load_certs(void); -extern void ac_list_certs(bool utc); - -extern certificate_t* ac_get_cert(identification_t *issuer, chunk_t serial); - -extern bool ac_verify_cert(certificate_t *ac, bool strict); - -extern bool match_group_membership(ietf_attributes_t *peer_attributes, - char *conn, - ietf_attributes_t *conn_attributes); - -#endif /* _AC_H */ diff --git a/src/pluto/adns.c b/src/pluto/adns.c deleted file mode 100644 index 76b459216..000000000 --- a/src/pluto/adns.c +++ /dev/null @@ -1,610 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program -- for internal use only! - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* This program executes as multiple processes. The Master process - * receives queries (struct adns_query messages) from Pluto and distributes - * them amongst Worker processes. These Worker processes are created - * by the Master whenever a query arrives and no existing Worker is free. - * At most MAX_WORKERS will be created; after that, the Master will queue - * queries until a Worker becomes free. When a Worker has an answer from - * the resolver, it sends the answer as a struct adns_answer message to the - * Master. The Master then forwards the answer to Pluto, noting that - * the Worker is free to accept another query. - * - * The protocol is simple: Pluto sends a sequence of queries and receives - * a sequence of answers. select(2) is used by Pluto and by the Master - * process to decide when to read, but writes are done without checking - * for readiness. Communications is via pipes. Since only one process - * can write to each pipe, messages will not be interleaved. Fixed length - * records are used for simplicity. - * - * Pluto needs a way to indicate to the Master when to shut down - * and the Master needs to indicate this to each worker. EOF on the pipe - * signifies this. - * - * The interfaces between these components are considered private to - * Pluto. This allows us to get away with less checking. This is a - * reason to use pipes instead of TCP/IP. - * - * Although the code uses plain old UNIX processes, it could be modified - * to use threads. That might reduce resource requirements. It would - * preclude running on systems without thread-safe resolvers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ??? for h_errno */ - -#include - -/* GCC magic! */ -#ifdef GCC_LINT -# define UNUSED __attribute__ ((unused)) -#else -# define UNUSED /* ignore */ -#endif - -#include "constants.h" -#include "adns.h" /* needs */ - -/* shared by all processes */ - -static const char *name; /* program name, for messages */ - -static bool debug = FALSE; - -/* Read a variable-length record from a pipe (and no more!). - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record read - * HES_OK if EOF - * HES_IO_ERROR_IN if errno tells the tale. - * Others are errors. - */ -static enum helper_exit_status -read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen) -{ - size_t n = 0; - size_t goal = minlen; - - do { - ssize_t m = read(fd, stuff + n, goal - n); - - if (m == -1) - { - if (errno != EINTR) - { - syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno)); - return HES_IO_ERROR_IN; - } - } - else if (m == 0) - { - return HES_OK; /* treat empty message as EOF */ - } - else - { - n += m; - if (n >= sizeof(size_t)) - { - goal = *(size_t *)(void *)stuff; - if (goal < minlen || maxlen < goal) - { - if (debug) - fprintf(stderr, "%lu : [%lu, %lu]\n" - , (unsigned long)goal - , (unsigned long)minlen, (unsigned long)maxlen); - return HES_BAD_LEN; - } - } - } - } while (n < goal); - - return HES_CONTINUE; -} - -/* Write a variable-length record to a pipe. - * First bytes must be a size_t containing the length. - * HES_CONTINUE if record written - * Others are errors. - */ -static enum helper_exit_status -write_pipe(int fd, const unsigned char *stuff) -{ - size_t len = *(const size_t *)(const void *)stuff; - size_t n = 0; - - do { - ssize_t m = write(fd, stuff + n, len - n); - - if (m == -1) - { - /* error, but ignore and retry if EINTR */ - if (errno != EINTR) - { - syslog(LOG_ERR, "Output error from master: %s", strerror(errno)); - return HES_IO_ERROR_OUT; - } - } - else - { - n += m; - } - } while (n != len); - return HES_CONTINUE; -} - -/**************** worker process ****************/ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -/* Support deprecated interface to allow for older releases of the resolver. - * Fake new interface! - * See resolver(3) bind distribution (should be in RHL6.1, but isn't). - * __RES was 19960801 in RHL6.2, an old resolver. - */ - -#if (__RES) <= 19960801 -# define OLD_RESOLVER 1 -#endif - -#ifdef OLD_RESOLVER - -# define res_ninit(statp) res_init() -# define res_nquery(statp, dname, class, type, answer, anslen) \ - res_query(dname, class, type, answer, anslen) -# define res_nclose(statp) res_close() - -static struct __res_state *statp = &_res; - -#else /* !OLD_RESOLVER */ - -static struct __res_state my_res_state /* = { 0 } */; -static res_state statp = &my_res_state; - -#endif /* !OLD_RESOLVER */ - -static int -worker(int qfd, int afd) -{ - { - int r = res_ninit(statp); - - if (r != 0) - { - syslog(LOG_ERR, "cannot initialize resolver"); - return HES_RES_INIT; - } -#ifndef OLD_RESOLVER - statp->options |= RES_ROTATE; -#endif - statp->options |= RES_DEBUG; - } - - for (;;) - { - struct adns_query q; - struct adns_answer a; - - enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q - , sizeof(q), sizeof(q)); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - - if (q.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in input from master: bad magic"); - return HES_BAD_MAGIC; - } - - a.amagic = ADNS_A_MAGIC; - a.serial = q.serial; - a.continuation = NULL; - - a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans)); - a.h_errno_val = h_errno; - - a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result); - -#ifdef DEBUG - if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY) - || ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT)) - sleep(30); /* delay the answer */ -#endif - - /* write answer, possibly a bit at a time */ - r = write_pipe(afd, (const unsigned char *)&a); - - if (r != HES_CONTINUE) - return r; /* some kind of exit */ - } -} - -/**************** master process ****************/ - -bool eof_from_pluto = FALSE; -#define PLUTO_QFD 0 /* queries come on stdin */ -#define PLUTO_AFD 1 /* answers go out on stdout */ - -#ifndef MAX_WORKERS -# define MAX_WORKERS 10 /* number of in-flight queries */ -#endif - -struct worker_info { - int qfd; /* query pipe's file descriptor */ - int afd; /* answer pipe's file descriptor */ - pid_t pid; - bool busy; - void *continuation; /* of outstanding request */ -}; - -static struct worker_info wi[MAX_WORKERS]; -static struct worker_info *wi_roof = wi; - -/* request FIFO */ - -struct query_list { - struct query_list *next; - struct adns_query aq; -}; - -static struct query_list *oldest_query = NULL; -static struct query_list *newest_query; /* undefined when oldest == NULL */ -static struct query_list *free_queries = NULL; - -static bool -spawn_worker(void) -{ - int qfds[2]; - int afds[2]; - pid_t p; - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno)); - exit(HES_PIPE); - } - - wi_roof->qfd = qfds[1]; /* write end of query pipe */ - wi_roof->afd = afds[0]; /* read end of answer pipe */ - - p = fork(); - if (p == -1) - { - /* fork failed: ignore if at least one worker exists */ - if (wi_roof == wi) - { - syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno)); - exit(HES_FORK); - } - close(qfds[0]); - close(qfds[1]); - close(afds[0]); - close(afds[1]); - return FALSE; - } - else if (p == 0) - { - /* child */ - struct worker_info *w; - - close(PLUTO_QFD); - close(PLUTO_AFD); - /* close all master pipes, including ours */ - for (w = wi; w <= wi_roof; w++) - { - close(w->qfd); - close(w->afd); - } - exit(worker(qfds[0], afds[1])); - } - else - { - /* parent */ - struct worker_info *w = wi_roof++; - - w->pid = p; - w->busy = FALSE; - close(qfds[0]); - close(afds[1]); - return TRUE; - } -} - -static void -send_eof(struct worker_info *w) -{ - pid_t p; - int status; - - close(w->qfd); - w->qfd = NULL_FD; - - close(w->afd); - w->afd = NULL_FD; - - /* reap child */ - p = waitpid(w->pid, &status, 0); - /* ignore result -- what could we do with it? */ -} - -static void -forward_query(struct worker_info *w) -{ - struct query_list *q = oldest_query; - - if (q == NULL) - { - if (eof_from_pluto) - send_eof(w); - } - else - { - enum helper_exit_status r - = write_pipe(w->qfd, (const unsigned char *) &q->aq); - - if (r != HES_CONTINUE) - exit(r); - - w->busy = TRUE; - - oldest_query = q->next; - q->next = free_queries; - free_queries = q; - } -} - -static void -query(void) -{ - struct query_list *q = free_queries; - enum helper_exit_status r; - - /* find an unused queue entry */ - if (q == NULL) - { - q = malloc(sizeof(*q)); - if (q == NULL) - { - syslog(LOG_ERR, "malloc(3) failed"); - exit(HES_MALLOC); - } - } - else - { - free_queries = q->next; - } - - r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq - , sizeof(q->aq), sizeof(q->aq)); - - if (r == HES_OK) - { - /* EOF: we're done, except for unanswered queries */ - struct worker_info *w; - - eof_from_pluto = TRUE; - q->next = free_queries; - free_queries = q; - - /* Send bye-bye to unbusy processes. - * Note that if there are queued queries, there won't be - * any non-busy workers. - */ - for (w = wi; w != wi_roof; w++) - if (!w->busy) - send_eof(w); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (q->aq.qmagic != ADNS_Q_MAGIC) - { - syslog(LOG_ERR, "error in query from Pluto: bad magic"); - exit(HES_BAD_MAGIC); - } - else - { - struct worker_info *w; - - /* got a query */ - - /* add it to FIFO */ - q->next = NULL; - if (oldest_query == NULL) - oldest_query = q; - else - newest_query->next = q; - newest_query = q; - - /* See if any worker available */ - for (w = wi; ; w++) - { - if (w == wi_roof) - { - /* no free worker */ - if (w == wi + MAX_WORKERS) - break; /* no more to be created */ - /* make a new one */ - if (!spawn_worker()) - break; /* cannot create one at this time */ - } - if (!w->busy) - { - /* assign first to free worker */ - forward_query(w); - break; - } - } - } - return; -} - -static void -answer(struct worker_info *w) -{ - struct adns_answer a; - enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a - , offsetof(struct adns_answer, ans), sizeof(a)); - - if (r == HES_OK) - { - /* unexpected EOF */ - syslog(LOG_ERR, "unexpected EOF from worker"); - exit(HES_IO_ERROR_IN); - } - else if (r != HES_CONTINUE) - { - exit(r); - } - else if (a.amagic != ADNS_A_MAGIC) - { - syslog(LOG_ERR, "Input from worker error: bad magic"); - exit(HES_BAD_MAGIC); - } - else if (a.continuation != w->continuation) - { - /* answer doesn't match query */ - syslog(LOG_ERR, "Input from worker error: continuation mismatch"); - exit(HES_SYNC); - } - else - { - /* pass the answer on to Pluto */ - enum helper_exit_status r - = write_pipe(PLUTO_AFD, (const unsigned char *) &a); - - if (r != HES_CONTINUE) - exit(r); - w->busy = FALSE; - forward_query(w); - } -} - -/* assumption: input limited; accept blocking on output */ -static int -master(void) -{ - for (;;) - { - fd_set readfds; - int maxfd = PLUTO_QFD; /* approximate lower bound */ - int ndes = 0; - struct worker_info *w; - - FD_ZERO(&readfds); - if (!eof_from_pluto) - { - FD_SET(PLUTO_QFD, &readfds); - ndes++; - } - for (w = wi; w != wi_roof; w++) - { - if (w->busy) - { - FD_SET(w->afd, &readfds); - ndes++; - if (maxfd < w->afd) - maxfd = w->afd; - } - } - - if (ndes == 0) - return HES_OK; /* done! */ - - do { - ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL); - } while (ndes == -1 && errno == EINTR); - if (ndes == -1) - { - syslog(LOG_ERR, "select(2) error: %s", strerror(errno)); - exit(HES_IO_ERROR_SELECT); - } - else if (ndes > 0) - { - if (FD_ISSET(PLUTO_QFD, &readfds)) - { - query(); - ndes--; - } - for (w = wi; ndes > 0 && w != wi_roof; w++) - { - if (w->busy && FD_ISSET(w->afd, &readfds)) - { - answer(w); - ndes--; - } - } - } - } -} - -/* Not to be invoked by strangers -- user hostile. - * Mandatory args: query-fd answer-fd - * Optional arg: -d, signifying "debug". - */ - -static void -adns_usage(const char *fmt, const char *arg) -{ - const char **sp = ipsec_copyright_notice(); - - fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n"); - - fprintf(stderr, fmt, arg); - fprintf(stderr, "\nstrongSwan "VERSION"\n"); - - for (; *sp != NULL; sp++) - fprintf(stderr, "%s\n", *sp); - - syslog(LOG_ERR, fmt, arg); - exit(HES_INVOCATION); -} - -int -main(int argc UNUSED, char **argv) -{ - int i = 1; - - name = argv[0]; - - while (i < argc) - { - if (streq(argv[i], "-d")) - { - i++; - debug = TRUE; - } - else - { - adns_usage("unexpected argument \"%s\"", argv[i]); - /*NOTREACHED*/ - } - } - - return master(); -} diff --git a/src/pluto/adns.h b/src/pluto/adns.h deleted file mode 100644 index dfbcbaf16..000000000 --- a/src/pluto/adns.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Pluto Asynchronous DNS Helper Program's Header - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ADNS - -/* dummy struct to make compilers happy */ -struct adns_query { -}; - -#else /* rest of file */ - -/* The interface in RHL6.x and BIND distribution 8.2.2 are different, - * so we build some of our own :-( - */ - -# ifndef NS_MAXDNAME -# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */ -# endif - -# ifndef NS_PACKETSZ -# define NS_PACKETSZ PACKETSZ -# endif - -/* protocol version */ - -#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4) -#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4) - -/* note: both struct adns_query and struct adns_answer must start with - * size_t len; - */ - -struct adns_query { - size_t len; - unsigned int qmagic; - unsigned long serial; - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - u_char name_buf[NS_MAXDNAME + 2]; - int type; /* T_KEY or T_TXT */ -}; - -struct adns_answer { - size_t len; - unsigned int amagic; - unsigned long serial; - struct adns_continuation *continuation; - int result; - int h_errno_val; - u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */ -}; - -enum helper_exit_status { - HES_CONTINUE = -1, /* not an exit */ - HES_OK = 0, /* all's well that ends well (perhaps EOF) */ - HES_INVOCATION, /* improper invocation */ - HES_IO_ERROR_SELECT, /* IO error in select() */ - HES_MALLOC, /* malloc failed */ - HES_IO_ERROR_IN, /* error reading pipe */ - HES_IO_ERROR_OUT, /* error reading pipe */ - HES_PIPE, /* pipe(2) failed */ - HES_SYNC, /* answer from worker doesn't match query */ - HES_FORK, /* fork(2) failed */ - HES_RES_INIT, /* resolver initialization failed */ - HES_BAD_LEN, /* implausible .len field */ - HES_BAD_MAGIC, /* .magic field wrong */ -}; -#endif /* ADNS */ diff --git a/src/pluto/alg_info.c b/src/pluto/alg_info.c deleted file mode 100644 index fe27c10b2..000000000 --- a/src/pluto/alg_info.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Algorithm info parsing and creation functions - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - - -#include "alg_info.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" -#include "crypto.h" -#include "kernel_alg.h" -#include "ike_alg.h" - -/* - * sadb/ESP aa attrib converters - */ -int alg_info_esp_aa2sadb(int auth) -{ - int sadb_aalg = 0; - - switch(auth) - { - case AUTH_ALGORITHM_HMAC_MD5: - case AUTH_ALGORITHM_HMAC_SHA1: - sadb_aalg = auth + 1; - break; - default: - sadb_aalg = auth; - } - return sadb_aalg; -} - -int alg_info_esp_sadb2aa(int sadb_aalg) -{ - int auth = 0; - - switch(sadb_aalg) - { - case SADB_AALG_MD5HMAC: - case SADB_AALG_SHA1HMAC: - auth = sadb_aalg - 1; - break; - default: - auth = sadb_aalg; - } - return auth; -} - -void alg_info_free(struct alg_info *alg_info) -{ - free(alg_info); -} - -/* - * Raw add routine: only checks for no duplicates - */ -static void __alg_info_esp_add(struct alg_info_esp *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits) -{ - struct esp_info *esp_info = alg_info->esp; - unsigned cnt = alg_info->alg_info_cnt, i; - - /* check for overflows */ - passert(cnt < countof(alg_info->esp)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (esp_info[i].esp_ealg_id == ealg_id - && (!ek_bits || esp_info[i].esp_ealg_keylen == ek_bits) - && esp_info[i].esp_aalg_id == aalg_id - && (!ak_bits || esp_info[i].esp_aalg_keylen == ak_bits)) - { - return; - } - } - - esp_info[cnt].esp_ealg_id = ealg_id; - esp_info[cnt].esp_ealg_keylen = ek_bits; - esp_info[cnt].esp_aalg_id = aalg_id; - esp_info[cnt].esp_aalg_keylen = ak_bits; - - /* sadb values */ - esp_info[cnt].encryptalg = ealg_id; - esp_info[cnt].authalg = alg_info_esp_aa2sadb(aalg_id); - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("esp alg added: %s_%d/%s, cnt=%d", - enum_show(&esp_transform_names, ealg_id), ek_bits, - enum_show(&auth_alg_names, aalg_id), - alg_info->alg_info_cnt) - ) -} - -/** - * Returns true if the given alg is an authenticated encryption algorithm - */ -static bool is_authenticated_encryption(int ealg_id) -{ - switch (ealg_id) - { - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_GMAC: - return TRUE; - } - return FALSE; -} - -/* - * Add ESP alg info _with_ logic (policy): - */ -static void alg_info_esp_add(struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits) -{ - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = ESP_3DES; - } - if (ealg_id > 0) - { - if (is_authenticated_encryption(ealg_id)) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_NONE, 0); - } - else if (aalg_id > 0) - { - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits); - } - else - { - /* Policy: default to SHA-1 and MD5 */ - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_SHA1, ak_bits); - __alg_info_esp_add((struct alg_info_esp *)alg_info, - ealg_id, ek_bits, - AUTH_ALGORITHM_HMAC_MD5, ak_bits); - } - } -} - -static void __alg_info_ike_add (struct alg_info_ike *alg_info, int ealg_id, - unsigned ek_bits, int aalg_id, unsigned ak_bits, - int modp_id) -{ - struct ike_info *ike_info = alg_info->ike; - unsigned cnt = alg_info->alg_info_cnt; - unsigned i; - - /* check for overflows */ - passert(cnt < countof(alg_info->ike)); - - /* dont add duplicates */ - for (i = 0; i < cnt; i++) - { - if (ike_info[i].ike_ealg == ealg_id - && (!ek_bits || ike_info[i].ike_eklen == ek_bits) - && ike_info[i].ike_halg == aalg_id - && (!ak_bits || ike_info[i].ike_hklen == ak_bits) - && ike_info[i].ike_modp==modp_id) - return; - } - - ike_info[cnt].ike_ealg = ealg_id; - ike_info[cnt].ike_eklen = ek_bits; - ike_info[cnt].ike_halg = aalg_id; - ike_info[cnt].ike_hklen = ak_bits; - ike_info[cnt].ike_modp = modp_id; - alg_info->alg_info_cnt++; - - DBG(DBG_CRYPT, - DBG_log("ikg alg added: %s_%d/%s/%s, cnt=%d", - enum_show(&oakley_enc_names, ealg_id), ek_bits, - enum_show(&oakley_hash_names, aalg_id), - enum_show(&oakley_group_names, modp_id), - alg_info->alg_info_cnt) - ) -} - -/* - * Proposals will be built by looping over default_ike_groups array and - * merging alg_info (ike_info) contents - */ - -static int default_ike_groups[] = { - MODP_1536_BIT, - MODP_1024_BIT -}; - -/* - * Add IKE alg info _with_ logic (policy): - */ -static void alg_info_ike_add (struct alg_info *alg_info, int ealg_id, - int ek_bits, int aalg_id, int ak_bits, int modp_id) -{ - int i = 0; - int n_groups = countof(default_ike_groups); - - /* if specified modp_id avoid loop over default_ike_groups */ - if (modp_id) - { - n_groups=0; - goto in_loop; - } - - for (; n_groups--; i++) - { - modp_id = default_ike_groups[i]; -in_loop: - /* Policy: default to 3DES */ - if (ealg_id == 0) - { - ealg_id = OAKLEY_3DES_CBC; - } - if (ealg_id > 0) - { - if (aalg_id > 0) - { - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - aalg_id, ak_bits, - modp_id); - } - else - { - /* Policy: default to MD5 and SHA */ - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_MD5, ak_bits, - modp_id); - __alg_info_ike_add((struct alg_info_ike *)alg_info, - ealg_id, ek_bits, - OAKLEY_SHA, ak_bits, - modp_id); - } - } - } -} - -static status_t alg_info_add(chunk_t alg, unsigned protoid, - int *ealg, size_t *ealg_keysize, - int *aalg, size_t *aalg_keysize, int *dh_group) -{ - const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len); - - if (token == NULL) - { - return FAILED; - } - switch (token->type) - { - case ENCRYPTION_ALGORITHM: - if (*ealg != 0) - { - return FAILED; - } - *ealg = (protoid == PROTO_ISAKMP) ? - oakley_from_encryption_algorithm(token->algorithm) : - esp_from_encryption_algorithm(token->algorithm); - if (*ealg == 0) - { - return FAILED; - } - *ealg_keysize = token->keysize; - break; - case INTEGRITY_ALGORITHM: - if (*aalg != 0) - { - return FAILED; - } - *aalg = (protoid == PROTO_ISAKMP) ? - oakley_from_integrity_algorithm(token->algorithm) : - esp_from_integrity_algorithm(token->algorithm); - if (*aalg == 0) - { - return FAILED; - } - *aalg_keysize = token->keysize; - break; - case DIFFIE_HELLMAN_GROUP: - if (protoid == PROTO_ISAKMP) - { - if (*dh_group != 0) - { - return FAILED; - } - *dh_group = token->algorithm; - } - break; - default: - return FAILED; - } - return SUCCESS; -} - - -static status_t alg_info_parse_str(struct alg_info *alg_info, char *alg_str) -{ - char *strict, *single; - status_t status = SUCCESS; - - strict = alg_str + strlen(alg_str) - 1; - if (*strict == '!') - { - alg_info->alg_info_flags |= ALG_INFO_F_STRICT; - *strict = '\0'; - } - while ((single = strsep(&alg_str, ","))) - { - chunk_t string = { (u_char *)single, strlen(single) }; - int ealg = 0; - int aalg = 0; - int dh_group = 0; - size_t ealg_keysize = 0; - size_t aalg_keysize = 0; - - eat_whitespace(&string); - - if (string.len > 0) - { - chunk_t alg; - - /* get all token, separated by '-' */ - while (extract_token(&alg, '-', &string)) - { - status |= alg_info_add(alg, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - if (string.len) - { - status |= alg_info_add(string, alg_info->alg_info_protoid, - &ealg, &ealg_keysize, - &aalg, &aalg_keysize, &dh_group); - } - } - if (status == SUCCESS) - - { - switch (alg_info->alg_info_protoid) - { - case PROTO_IPSEC_ESP: - alg_info_esp_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize); - break; - case PROTO_ISAKMP: - alg_info_ike_add(alg_info, ealg, ealg_keysize, - aalg, aalg_keysize, - dh_group); - break; - default: - break; - } - } - } - return status; -} - -struct alg_info_esp *alg_info_esp_create_from_str(char *alg_str) -{ - struct alg_info_esp *alg_info_esp; - char esp_buf[BUF_LEN]; - char *pfs_name; - status_t status = SUCCESS; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_esp = malloc_thing (struct alg_info_esp); - zero(alg_info_esp); - - pfs_name=strchr(alg_str, ';'); - if (pfs_name) - { - memcpy(esp_buf, alg_str, pfs_name-alg_str); - esp_buf[pfs_name-alg_str] = 0; - alg_str = esp_buf; - pfs_name++; - - /* if pfs strings AND first char is not '0' */ - if (*pfs_name && pfs_name[0] != '0') - { - const proposal_token_t *token; - - token = proposal_get_token(pfs_name, strlen(pfs_name)); - if (token == NULL || token->type != DIFFIE_HELLMAN_GROUP) - { - /* Bomb if pfsgroup not found */ - DBG(DBG_CRYPT, - DBG_log("alg_info_esp_create_from_str(): pfsgroup \"%s\" not found" - , pfs_name) - ) - status = FAILED; - goto out; - } - alg_info_esp->esp_pfsgroup = token->algorithm; - } - } - else - { - alg_info_esp->esp_pfsgroup = 0; - } - alg_info_esp->alg_info_protoid = PROTO_IPSEC_ESP; - status = alg_info_parse_str((struct alg_info *)alg_info_esp, alg_str); - -out: - if (status == SUCCESS) - { - alg_info_esp->ref_cnt = 1; - return alg_info_esp; - } - else - { - free(alg_info_esp); - return NULL; - } -} - -struct alg_info_ike *alg_info_ike_create_from_str(char *alg_str) -{ - struct alg_info_ike *alg_info_ike; - /* - * alg_info storage should be sized dynamically - * but this may require 2passes to know - * transform count in advance. - */ - alg_info_ike = malloc_thing (struct alg_info_ike); - zero(alg_info_ike); - alg_info_ike->alg_info_protoid = PROTO_ISAKMP; - - if (alg_info_parse_str((struct alg_info *)alg_info_ike, alg_str) == SUCCESS) - { - alg_info_ike->ref_cnt = 1; - return alg_info_ike; - } - else - { - free(alg_info_ike); - return NULL; - } -} - -/* - * alg_info struct can be shared by - * several connections instances, - * handle free() with ref_cnts - */ -void -alg_info_addref(struct alg_info *alg_info) -{ - if (alg_info != NULL) - { - alg_info->ref_cnt++; - } -} - -void -alg_info_delref(struct alg_info **alg_info_p) -{ - struct alg_info *alg_info = *alg_info_p; - - if (alg_info != NULL) - { - passert(alg_info->ref_cnt != 0); - alg_info->ref_cnt--; - if (alg_info->ref_cnt == 0) - { - alg_info_free(alg_info); - } - *alg_info_p = NULL; - } -} - -/* snprint already parsed transform list (alg_info) */ -int -alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info) -{ - char *ptr = buf; - int np = 0; - struct esp_info *esp_info; - struct ike_info *ike_info; - int cnt; - - switch (alg_info->alg_info_protoid) { - case PROTO_IPSEC_ESP: - { - struct alg_info_esp *alg_info_esp = (struct alg_info_esp *)alg_info; - - ALG_INFO_ESP_FOREACH(alg_info_esp, esp_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&esp_transform_names, esp_info->esp_ealg_id)); - ptr += np; - buflen -= np; - if (esp_info->esp_ealg_keylen) - { - np = snprintf(ptr, buflen, "_%zu", esp_info->esp_ealg_keylen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s, ", - enum_show(&auth_alg_names, esp_info->esp_aalg_id)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - if (alg_info_esp->esp_pfsgroup) - { - np = snprintf(ptr, buflen, "; pfsgroup=%s; ", - enum_show(&oakley_group_names, alg_info_esp->esp_pfsgroup)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - } - - case PROTO_ISAKMP: - ALG_INFO_IKE_FOREACH((struct alg_info_ike *)alg_info, ike_info, cnt) - { - np = snprintf(ptr, buflen, "%s", - enum_show(&oakley_enc_names, ike_info->ike_ealg)); - ptr += np; - buflen -= np; - if (ike_info->ike_eklen) - { - np = snprintf(ptr, buflen, "_%zu", ike_info->ike_eklen); - ptr += np; - buflen -= np; - } - np = snprintf(ptr, buflen, "/%s/%s, ", - enum_show(&oakley_hash_names, ike_info->ike_halg), - enum_show(&oakley_group_names, ike_info->ike_modp)); - ptr += np; - buflen -= np; - if (buflen < 0) - goto out; - } - break; - default: - np = snprintf(buf, buflen, "INVALID protoid=%d\n" - , alg_info->alg_info_protoid); - ptr += np; - buflen -= np; - goto out; - } - - np = snprintf(ptr, buflen, "%s" - , alg_info->alg_info_flags & ALG_INFO_F_STRICT? - "strict":""); - ptr += np; - buflen -= np; -out: - if (buflen < 0) - { - loglog(RC_LOG_SERIOUS - , "buffer space exhausted in alg_info_snprint_ike(), buflen=%d" - , buflen); - } - - return ptr - buf; -} - -int alg_info_snprint_esp(char *buf, int buflen, struct alg_info_esp *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct esp_info *esp_info = alg_info->esp; - - while (cnt--) - { - if (kernel_alg_esp_enc_ok(esp_info->esp_ealg_id, 0, NULL) - && kernel_alg_esp_auth_ok(esp_info->esp_aalg_id, NULL)) - { - u_int eklen = (esp_info->esp_ealg_keylen) - ? esp_info->esp_ealg_keylen - : kernel_alg_esp_enc_keylen(esp_info->esp_ealg_id) - * BITS_PER_BYTE; - - u_int aklen = esp_info->esp_aalg_keylen - ? esp_info->esp_aalg_keylen - : kernel_alg_esp_auth_keylen(esp_info->esp_aalg_id) - * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d, ", - esp_info->esp_ealg_id, eklen, - esp_info->esp_aalg_id, aklen); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - esp_info++; - } - return ptr - buf; -} - -int alg_info_snprint_ike(char *buf, int buflen, struct alg_info_ike *alg_info) -{ - char *ptr = buf; - - int cnt = alg_info->alg_info_cnt; - struct ike_info *ike_info = alg_info->ike; - - while (cnt--) - { - struct encrypt_desc *enc_desc = ike_alg_get_crypter(ike_info->ike_ealg); - struct hash_desc *hash_desc = ike_alg_get_hasher(ike_info->ike_halg); - struct dh_desc *dh_desc = ike_alg_get_dh_group(ike_info->ike_modp); - - if (enc_desc && hash_desc && dh_desc) - { - - u_int eklen = (ike_info->ike_eklen) - ? ike_info->ike_eklen - : enc_desc->keydeflen; - - u_int aklen = (ike_info->ike_hklen) - ? ike_info->ike_hklen - : hash_desc->hash_digest_size * BITS_PER_BYTE; - - int ret = snprintf(ptr, buflen, "%d_%03d-%d_%03d-%d, ", - ike_info->ike_ealg, eklen, - ike_info->ike_halg, aklen, - ike_info->ike_modp); - ptr += ret; - buflen -= ret; - if (buflen < 0) - break; - } - ike_info++; - } - return ptr - buf; -} - diff --git a/src/pluto/alg_info.h b/src/pluto/alg_info.h deleted file mode 100644 index 85b88ddff..000000000 --- a/src/pluto/alg_info.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Algorithm info parsing and creation functions - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef ALG_INFO_H -#define ALG_INFO_H - -struct esp_info { - u_int8_t transid; /* ESP transform */ - u_int16_t auth; /* AUTH */ - size_t enckeylen; /* keylength for ESP transform */ - size_t authkeylen; /* keylength for AUTH */ - u_int8_t encryptalg; /* normally encryptalg=transid */ - u_int8_t authalg; /* normally authalg=auth+1 */ -}; - -struct ike_info { - u_int16_t ike_ealg; /* high 16 bit nums for reserved */ - u_int8_t ike_halg; - size_t ike_eklen; - size_t ike_hklen; - u_int16_t ike_modp; -}; - -#define ALG_INFO_COMMON \ - int alg_info_cnt; \ - int ref_cnt; \ - unsigned alg_info_flags; \ - unsigned alg_info_protoid - -struct alg_info { - ALG_INFO_COMMON; -}; - -struct alg_info_esp { - ALG_INFO_COMMON; - struct esp_info esp[64]; - int esp_pfsgroup; -}; - -struct alg_info_ike { - ALG_INFO_COMMON; - struct ike_info ike[64]; -}; -#define esp_ealg_id transid -#define esp_aalg_id auth -#define esp_ealg_keylen enckeylen /* bits */ -#define esp_aalg_keylen authkeylen /* bits */ - -/* alg_info_flags bits */ -#define ALG_INFO_F_STRICT 0x01 - -extern int alg_info_esp_aa2sadb(int auth); -extern int alg_info_esp_sadb2aa(int sadb_aalg); -extern void alg_info_free(struct alg_info *alg_info); -extern void alg_info_addref(struct alg_info *alg_info); -extern void alg_info_delref(struct alg_info **alg_info); -extern struct alg_info_esp* alg_info_esp_create_from_str(char *alg_str); -extern struct alg_info_ike* alg_info_ike_create_from_str(char *alg_str); -extern int alg_info_parse(const char *str); -extern int alg_info_snprint(char *buf, int buflen, struct alg_info *alg_info); -extern int alg_info_snprint_esp(char *buf, int buflen - , struct alg_info_esp *alg_info); -extern int alg_info_snprint_ike(char *buf, int buflen - , struct alg_info_ike *alg_info); -#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \ - for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++) -#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \ - for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++) -#endif /* ALG_INFO_H */ diff --git a/src/pluto/builder.c b/src/pluto/builder.c deleted file mode 100644 index a6e05a330..000000000 --- a/src/pluto/builder.c +++ /dev/null @@ -1,150 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2002-2009 Andreas Steffen - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "builder.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "crl.h" - -/** - * Load a certificate - */ -static cert_t *builder_load_cert(certificate_type_t type, va_list args) -{ - x509_flag_t flags = 0; - chunk_t blob = chunk_empty; - bool pgp = FALSE; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_PGP: - pgp = TRUE; - /* FALL */ - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_X509_FLAG: - flags |= va_arg(args, x509_flag_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - cert_t *cert = malloc_thing(cert_t); - - *cert = cert_empty; - - if (pgp) - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_GPG, - BUILD_BLOB_PGP, blob, - BUILD_END); - } - else - { - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_X509_FLAG, flags, - BUILD_END); - } - if (cert->cert) - { - return cert; - } - plog(" error in X.509 certificate"); - cert_free(cert); - } - return NULL; -} - -/** - * Load a CRL - */ -static x509crl_t *builder_load_crl(certificate_type_t type, va_list args) -{ - chunk_t blob = chunk_empty; - x509crl_t *crl; - - while (TRUE) - { - switch (va_arg(args, builder_part_t)) - { - case BUILD_BLOB_ASN1_DER: - blob = va_arg(args, chunk_t); - continue; - case BUILD_END: - break; - default: - return NULL; - } - break; - } - if (blob.ptr) - { - crl = malloc_thing(x509crl_t); - crl->next = NULL; - crl->distributionPoints = linked_list_create(); - crl->crl = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509_CRL, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (crl->crl) - { - return crl; - } - plog(" error in X.509 crl"); - free_crl(crl); - } - return NULL; -} - -void init_builder(void) -{ - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, FALSE, - (builder_function_t)builder_load_cert); - lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, FALSE, - (builder_function_t)builder_load_crl); -} - -void free_builder(void) -{ - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_cert); - lib->creds->remove_builder(lib->creds, (builder_function_t)builder_load_crl); -} - diff --git a/src/pluto/builder.h b/src/pluto/builder.h deleted file mode 100644 index 784751b7c..000000000 --- a/src/pluto/builder.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Pluto certificate/CRL/AC builder hooks. - * Copyright (C) 2009 Martin Willi - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _BUILDER_H -#define _BUILDER_H - -/* register credential builder hooks */ -extern void init_builder(); -/* unregister credential builder hooks */ -extern void free_builder(); - -#endif /* _BUILDER_H */ diff --git a/src/pluto/ca.c b/src/pluto/ca.c deleted file mode 100644 index 827b98121..000000000 --- a/src/pluto/ca.c +++ /dev/null @@ -1,712 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "smartcard.h" - -/* chained list of X.509 authority certificates (ca, aa, and ocsp) */ - -static cert_t *x509authcerts = NULL; - -/* chained list of X.509 certification authority information records */ - -static ca_info_t *ca_infos = NULL; - -/* - * Checks if CA a is trusted by CA b - */ -bool trusted_ca(identification_t *a, identification_t *b, int *pathlen) -{ - bool match = FALSE; - - /* no CA b specified -> any CA a is accepted */ - if (b == NULL) - { - *pathlen = (a == NULL) ? 0 : X509_MAX_PATH_LEN; - return TRUE; - } - - /* no CA a specified -> trust cannot be established */ - if (a == NULL) - { - *pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - - *pathlen = 0; - - /* CA a equals CA b -> we have a match */ - if (a->equals(a, b)) - { - return TRUE; - } - - /* CA a might be a subordinate CA of b */ - lock_authcert_list("trusted_ca"); - - while ((*pathlen)++ < X509_MAX_PATH_LEN) - { - certificate_t *certificate; - identification_t *issuer; - cert_t *cacert; - - cacert = get_authcert(a, chunk_empty, X509_CA); - if (cacert == NULL) - { - break; - } - certificate = cacert->cert; - - /* is the certificate self-signed? */ - { - x509_t *x509 = (x509_t*)certificate; - - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - break; - } - } - - /* does the issuer of CA a match CA b? */ - issuer = certificate->get_issuer(certificate); - match = b->equals(b, issuer); - - /* we have a match and exit the loop */ - if (match) - { - break; - } - /* go one level up in the CA chain */ - a = issuer; - } - - unlock_authcert_list("trusted_ca"); - return match; -} - -/* - * does our CA match one of the requested CAs? - */ -bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca, - int *our_pathlen) -{ - identification_t *ca; - enumerator_t *enumerator; - - /* if no ca is requested than any ca will match */ - if (requested_ca == NULL || requested_ca->get_count(requested_ca) == 0) - { - *our_pathlen = 0; - return TRUE; - } - - *our_pathlen = X509_MAX_PATH_LEN + 1; - - enumerator = requested_ca->create_enumerator(requested_ca); - while (enumerator->enumerate(enumerator, &ca)) - { - int pathlen; - - if (trusted_ca(our_ca, ca, &pathlen) && pathlen < *our_pathlen) - { - *our_pathlen = pathlen; - } - } - enumerator->destroy(enumerator); - - if (*our_pathlen > X509_MAX_PATH_LEN) - { - *our_pathlen = X509_MAX_PATH_LEN; - return FALSE; - } - else - { - return TRUE; - } -} - -/* - * free the first authority certificate in the chain - */ -static void free_first_authcert(void) -{ - cert_t *first = x509authcerts; - - x509authcerts = first->next; - cert_free(first); -} - -/* - * free all CA certificates - */ -void free_authcerts(void) -{ - lock_authcert_list("free_authcerts"); - - while (x509authcerts != NULL) - { - free_first_authcert(); - } - unlock_authcert_list("free_authcerts"); -} - -/* - * get a X.509 authority certificate with a given subject or keyid - */ -cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags) -{ - cert_t *cert, *prev_cert = NULL; - - /* the authority certificate list is empty */ - if (x509authcerts == NULL) - { - return NULL; - } - - for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - - /* skip non-matching types of authority certificates */ - if (!(x509->get_flags(x509) & auth_flags)) - { - continue; - } - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!(subject && certificate->has_subject(certificate, subject)) && - (subject || !keyid.ptr)) - { - continue; - } - - /* found the authcert */ - if (cert != x509authcerts) - { - /* bring the certificate up front */ - prev_cert->next = cert->next; - cert->next = x509authcerts; - x509authcerts = cert; - } - return cert; - } - return NULL; -} - -/* - * add an authority certificate to the chained list - */ -cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - cert_t *old_cert; - - lock_authcert_list("add_authcert"); - - old_cert = get_authcert(certificate->get_subject(certificate), - x509->get_subjectKeyIdentifier(x509), - auth_flags); - if (old_cert) - { - if (certificate->equals(certificate, old_cert->cert)) - { - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" authcert is already present and identical") - ) - unlock_authcert_list("add_authcert"); - - cert_free(cert); - return old_cert; - } - else - { - /* cert is already present but will be replaced by new cert */ - free_first_authcert(); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log(" existing authcert deleted") - ) - } - } - - /* add new authcert to chained list */ - cert->next = x509authcerts; - x509authcerts = cert; - cert_share(cert); /* set count to one */ - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" authcert inserted") - ) - unlock_authcert_list("add_authcert"); - return cert; -} - -/* - * Loads authority certificates - */ -void load_authcerts(char *type, char *path, x509_flag_t auth_flags) -{ - enumerator_t *enumerator; - struct stat st; - char *file; - - DBG1(DBG_LIB, "loading %s certificates from '%s'", type, path); - - enumerator = enumerator_create_directory(path); - if (!enumerator) - { - DBG1(DBG_LIB, " reading directory '%s' failed", path); - return; - } - - while (enumerator->enumerate(enumerator, NULL, &file, &st)) - { - cert_t *cert; - - if (!S_ISREG(st.st_mode)) - { - /* skip special file */ - continue; - } - cert = load_cert(file, type, auth_flags); - if (cert) - { - add_authcert(cert, auth_flags); - } - } - enumerator->destroy(enumerator); -} - -/* - * list all X.509 authcerts with given auth flags in a chained list - */ -void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc) -{ - lock_authcert_list("list_authcerts"); - list_x509cert_chain(caption, x509authcerts, auth_flags, utc); - unlock_authcert_list("list_authcerts"); -} - -/* - * get a cacert with a given subject or keyid from an alternative list - */ -static const cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid, - const cert_t *cert) -{ - if (cert == NULL) - { - return NULL; - } - for (; cert != NULL; cert = cert->next) - { - certificate_t *certificate = cert->cert; - - /* compare the keyid with the certificate's subjectKeyIdentifier */ - if (keyid.ptr) - { - x509_t *x509 = (x509_t*)certificate; - chunk_t subjectKeyId; - - subjectKeyId = x509->get_subjectKeyIdentifier(x509); - if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId)) - { - continue; - } - } - - /* compare the subjectDistinguishedNames */ - if (!certificate->has_subject(certificate, subject)) - { - continue; - } - - /* we found the cacert */ - return cert; - } - return NULL; -} - -/* establish trust into a candidate authcert by going up the trust chain. - * validity and revocation status are not checked. - */ -bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain) -{ - int pathlen; - - lock_authcert_list("trust_authcert_candidate"); - - for (pathlen = 0; pathlen < X509_MAX_PATH_LEN; pathlen++) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - const cert_t *authcert = NULL; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr != NULL) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - /* search in alternative chain first */ - authcert = get_alt_cacert(issuer, authKeyID, alt_chain); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found in alternative chain") - ) - } - else - { - /* search in trusted chain */ - authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert != NULL) - { - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - } - else - { - plog("issuer cacert not found"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - } - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check if cert is a self-signed root ca */ - if (pathlen > 0 && (x509->get_flags(x509) & X509_SELF_SIGNED)) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca") - ) - unlock_authcert_list("trust_authcert_candidate"); - return TRUE; - } - - /* go up one step in the trust chain */ - cert = authcert; - } - plog("maximum ca path length of %d levels exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("trust_authcert_candidate"); - return FALSE; -} - -/* - * get a CA info record with a given authName or authKeyID - */ -ca_info_t* get_ca_info(identification_t *name, chunk_t keyid) -{ - ca_info_t *ca= ca_infos; - - while (ca != NULL) - { - if ((keyid.ptr) ? same_keyid(keyid, ca->authKeyID) - : name->equals(name, ca->authName)) - { - return ca; - } - ca = ca->next; - } - return NULL; -} - - -/* - * free the dynamic memory used by a ca_info record - */ -static void -free_ca_info(ca_info_t* ca_info) -{ - if (ca_info == NULL) - { - return; - } - ca_info->crluris->destroy_function(ca_info->crluris, free); - DESTROY_IF(ca_info->authName); - free(ca_info->name); - free(ca_info->ldaphost); - free(ca_info->ldapbase); - free(ca_info->ocspuri); - free(ca_info->authKeyID.ptr); - free(ca_info); -} - -/* - * free all CA certificates - */ -void free_ca_infos(void) -{ - while (ca_infos != NULL) - { - ca_info_t *ca = ca_infos; - - ca_infos = ca_infos->next; - free_ca_info(ca); - } -} - -/* - * find a CA information record by name and optionally delete it - */ -bool find_ca_info_by_name(const char *name, bool delete) -{ - ca_info_t **ca_p = &ca_infos; - ca_info_t *ca = *ca_p; - - while (ca != NULL) - { - /* is there already an entry? */ - if (streq(name, ca->name)) - { - if (delete) - { - lock_ca_info_list("find_ca_info_by_name"); - *ca_p = ca->next; - free_ca_info(ca); - plog("deleting ca description \"%s\"", name); - unlock_ca_info_list("find_ca_info_by_name"); - } - return TRUE; - } - ca_p = &ca->next; - ca = *ca_p; - } - return FALSE; -} - -/* - * Create an empty ca_info_t record - */ -ca_info_t* create_ca_info(void) -{ - ca_info_t *ca_info = malloc_thing(ca_info_t); - - memset(ca_info, 0, sizeof(ca_info_t)); - ca_info->crluris = linked_list_create(); - - return ca_info; -} - -/** - * Adds a CA description to a chained list - */ -void add_ca_info(const whack_message_t *msg) -{ - smartcard_t *sc = NULL; - cert_t *cert = NULL; - bool cached_cert = FALSE; - - if (find_ca_info_by_name(msg->name, FALSE)) - { - loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name); - return; - } - - if (scx_on_smartcard(msg->cacert)) - { - /* load CA cert from smartcard */ - cert = scx_load_cert(msg->cacert, &sc, &cached_cert); - } - else - { - /* load CA cert from file */ - cert = load_ca_cert(msg->cacert); - } - - if (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - chunk_t subjectKeyID = x509->get_subjectKeyIdentifier(x509); - ca_info_t *ca = NULL; - - /* does the authname already exist? */ - ca = get_ca_info(subject, subjectKeyID); - - if (ca != NULL) - { - /* ca_info is already present */ - loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found," - "ignoring \"%s\"", ca->name, msg->name); - cert_free(cert); - return; - } - - plog("added ca description \"%s\"", msg->name); - - /* create and initialize new ca_info record */ - ca = create_ca_info(); - - /* name */ - ca->name = clone_str(msg->name); - - /* authName */ - ca->authName = subject->clone(subject); - DBG(DBG_CONTROL, - DBG_log("authname: '%Y'", subject) - ) - - /* authKeyID */ - if (subjectKeyID.ptr) - { - ca->authKeyID = chunk_clone(subjectKeyID); - DBG(DBG_CONTROL | DBG_PARSING , - DBG_log("authkey: %#B", &subjectKeyID) - ) - } - - /* ldaphost */ - ca->ldaphost = clone_str(msg->ldaphost); - - /* ldapbase */ - ca->ldapbase = clone_str(msg->ldapbase); - - /* ocspuri */ - if (msg->ocspuri != NULL) - { - if (strncasecmp(msg->ocspuri, "http", 4) == 0) - ca->ocspuri = clone_str(msg->ocspuri); - else - plog(" ignoring ocspuri with unknown protocol"); - } - - /* add crl uris */ - add_distribution_point(ca->crluris, msg->crluri); - add_distribution_point(ca->crluris, msg->crluri2); - - /* strictrlpolicy */ - ca->strictcrlpolicy = msg->whack_strict; - - /* insert ca_info record into the chained list */ - lock_ca_info_list("add_ca_info"); - - ca->next = ca_infos; - ca_infos = ca; - - unlock_ca_info_list("add_ca_info"); - - /* add cacert to list of authcerts */ - cert = add_authcert(cert, X509_CA); - if (!cached_cert && sc != NULL) - { - if (sc->last_cert != NULL) - { - sc->last_cert->count--; - } - sc->last_cert = cert; - cert_share(sc->last_cert); - } - if (sc != NULL) - time(&sc->last_load); - } -} - -/* - * list all ca_info records in the chained list - */ -void list_ca_infos(bool utc) -{ - ca_info_t *ca = ca_infos; - - if (ca != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CA Information Records:"); - } - - while (ca != NULL) - { - /* strictpolicy per CA not supported yet - * - whack_log(RC_COMMENT, "%T, \"%s\", strictcrlpolicy: %s" - , &ca->installed, utc, ca->name - , ca->strictcrlpolicy? "yes":"no"); - */ - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " authname: \"%Y\"", ca->authName); - if (ca->ldaphost) - { - whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost); - } - if (ca->ldapbase) - { - whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase); - } - if (ca->ocspuri) - { - whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri); - } - - list_distribution_points(ca->crluris); - - if (ca->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &ca->authKeyID); - } - ca = ca->next; - } -} - diff --git a/src/pluto/ca.h b/src/pluto/ca.h deleted file mode 100644 index d964a694a..000000000 --- a/src/pluto/ca.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Certification Authority (CA) support for IKE authentication - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CA_H -#define _CA_H - -#include -#include - -#include "certs.h" -#include "whack.h" - -/* CA info structures */ - -typedef struct ca_info ca_info_t; - -struct ca_info { - ca_info_t *next; - char *name; - identification_t *authName; - chunk_t authKeyID; - char *ldaphost; - char *ldapbase; - char *ocspuri; - linked_list_t *crluris; - bool strictcrlpolicy; -}; - -extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen); -extern bool match_requested_ca(linked_list_t *requested_ca, - identification_t *our_ca, int *our_pathlen); -extern cert_t* get_authcert(identification_t *subject, chunk_t keyid, - x509_flag_t auth_flags); -extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags); -extern cert_t* add_authcert(cert_t *cert, x509_flag_t auth_flags); -extern void free_authcerts(void); -extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc); -extern bool trust_authcert_candidate(const cert_t *cert, const cert_t *alt_chain); -extern ca_info_t* get_ca_info(identification_t *name, chunk_t keyid); -extern bool find_ca_info_by_name(const char *name, bool delete); -extern void add_ca_info(const whack_message_t *msg); -extern void delete_ca_info(const char *name); -extern void free_ca_infos(void); -extern void list_ca_infos(bool utc); - -#endif /* _CA_H */ - diff --git a/src/pluto/certs.c b/src/pluto/certs.c deleted file mode 100644 index e866022df..000000000 --- a/src/pluto/certs.c +++ /dev/null @@ -1,268 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "certs.h" -#include "whack.h" -#include "fetch.h" -#include "keys.h" -#include "builder.h" - -/** - * Initialization - */ -const cert_t cert_empty = { - NULL , /* cert */ - NULL , /* *next */ - 0 , /* count */ - FALSE /* smartcard */ -}; - -/** - * Chained lists of X.509 and PGP end entity certificates - */ -static cert_t *certs = NULL; - -/** - * Free a pluto certificate - */ -void cert_free(cert_t *cert) -{ - if (cert) - { - certificate_t *certificate = cert->cert; - - if (certificate) - { - certificate->destroy(certificate); - } - free(cert); - } -} - -/** - * Add a pluto end entity certificate to the chained list - */ -cert_t* cert_add(cert_t *cert) -{ - certificate_t *certificate = cert->cert; - cert_t *c; - - lock_certs_and_keys("cert_add"); - - for (c = certs; c != NULL; c = c->next) - { - if (certificate->equals(certificate, c->cert)) - { /* already in chain, free cert */ - unlock_certs_and_keys("cert_add"); - cert_free(cert); - return c; - } - } - - /* insert new cert at the root of the chain */ - cert->next = certs; - certs = cert; - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log(" cert inserted") - ) - unlock_certs_and_keys("cert_add"); - return cert; -} - -/** - * Loads a X.509 or OpenPGP certificate - */ -cert_t* load_cert(char *filename, const char *label, x509_flag_t flags) -{ - cert_t *cert; - - cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CERT, - BUILD_FROM_FILE, filename, - BUILD_X509_FLAG, flags, - BUILD_END); - if (cert) - { - plog(" loaded %s certificate from '%s'", label, filename); - } - return cert; -} - -/** - * Loads a host certificate - */ -cert_t* load_host_cert(char *filename) -{ - char *path = concatenate_paths(HOST_CERT_PATH, filename); - - return load_cert(path, "host", X509_NONE); -} - -/** - * Loads a CA certificate - */ -cert_t* load_ca_cert(char *filename) -{ - char *path = concatenate_paths(CA_CERT_PATH, filename); - - return load_cert(path, "CA", X509_NONE); -} - -/** - * for each link pointing to the certificate increase the count by one - */ -void cert_share(cert_t *cert) -{ - if (cert != NULL) - { - cert->count++; - } -} - -/* release of a certificate decreases the count by one - * the certificate is freed when the counter reaches zero - */ -void cert_release(cert_t *cert) -{ - if (cert && --cert->count == 0) - { - cert_t **pp = &certs; - while (*pp != cert) - { - pp = &(*pp)->next; - } - *pp = cert->next; - cert_free(cert); - } -} - -/** - * Get a X.509 certificate with a given issuer found at a certain position - */ -cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t *chain) -{ - cert_t *cert = chain ? chain->next : certs; - - while (cert) - { - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - - if (keyid.ptr ? same_keyid(keyid, authKeyID) : - certificate->has_issuer(certificate, issuer)) - { - return cert; - } - cert = cert->next; - } - return NULL; -} - -/** - * List all PGP end certificates in a chained list - */ -void list_pgp_end_certs(bool utc) -{ - cert_t *cert = certs; - time_t now = time(NULL); - bool first = TRUE; - - - while (cert != NULL) - { - certificate_t *certificate = cert->cert; - - if (certificate->get_type(certificate) == CERT_GPG) - { - time_t created, until; - public_key_t *key; - identification_t *userid = certificate->get_subject(certificate); - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of PGP End Entity Certificates:"); - first = false; - } - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " userid: '%Y'", userid); - whack_log(RC_COMMENT, " digest: %#B", &fingerprint); - - /* list validity */ - certificate->get_validity(certificate, &now, &created, &until); - whack_log(RC_COMMENT, " created: %T", &created, utc); - whack_log(RC_COMMENT, " until: %T %s%s", &until, utc, - check_expiry(until, CA_CERT_WARNING_INTERVAL, TRUE), - (until == TIME_32_BIT_SIGNED_MAX) ? " (expires never)":""); - - key = certificate->get_public_key(certificate); - if (key) - { - chunk_t keyid; - - whack_log(RC_COMMENT, " pubkey: %N %4d bits%s", - key_type_names, key->get_type(key), - key->get_keysize(key), - has_private_key(cert)? ", has private key" : ""); - if (key->get_fingerprint(key, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " keyid: %#B", &keyid); - } - if (key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - whack_log(RC_COMMENT, " subjkey: %#B", &keyid); - } - } - } - cert = cert->next; - } -} - -/** - * List all X.509 end certificates in a chained list - */ -void list_x509_end_certs(bool utc) -{ - list_x509cert_chain("End Entity", certs, X509_NONE, utc); -} - -/** - * list all X.509 and OpenPGP end certificates - */ -void cert_list(bool utc) -{ - list_x509_end_certs(utc); - list_pgp_end_certs(utc); -} - diff --git a/src/pluto/certs.h b/src/pluto/certs.h deleted file mode 100644 index b31c4c3ed..000000000 --- a/src/pluto/certs.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Certificate support for IKE authentication - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CERTS_H -#define _CERTS_H - -#include -#include -#include - -#include - -#include "defs.h" - -/* path definitions for private keys, end certs, - * cacerts, attribute certs and crls - */ -#define PRIVATE_KEY_PATH IPSEC_CONFDIR "/ipsec.d/private" -#define HOST_CERT_PATH IPSEC_CONFDIR "/ipsec.d/certs" -#define CA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/cacerts" -#define A_CERT_PATH IPSEC_CONFDIR "/ipsec.d/acerts" -#define AA_CERT_PATH IPSEC_CONFDIR "/ipsec.d/aacerts" -#define OCSP_CERT_PATH IPSEC_CONFDIR "/ipsec.d/ocspcerts" -#define CRL_PATH IPSEC_CONFDIR "/ipsec.d/crls" -#define REQ_PATH IPSEC_CONFDIR "/ipsec.d/reqs" - -/* advance warning of imminent expiry of - * cacerts, public keys, and crls - */ -#define CA_CERT_WARNING_INTERVAL 30 /* days */ -#define OCSP_CERT_WARNING_INTERVAL 30 /* days */ -#define PUBKEY_WARNING_INTERVAL 7 /* days */ -#define CRL_WARNING_INTERVAL 7 /* days */ -#define ACERT_WARNING_INTERVAL 1 /* day */ - -/* access structure for a pluto certificate */ - -typedef struct cert_t cert_t; - -struct cert_t { - certificate_t *cert; - cert_t *next; - int count; - bool smartcard; -}; - -/* used for initialization */ -extern const cert_t cert_empty; - -/* do not send certificate requests - * flag set in plutomain.c and used in ipsec_doi.c - */ -extern bool no_cr_send; - -extern cert_t* load_cert(char *filename, const char *label, x509_flag_t flags); -extern cert_t* load_host_cert(char *filename); -extern cert_t* load_ca_cert(char *filename); -extern cert_t* cert_add(cert_t *cert); -extern void cert_free(cert_t *cert); -extern void cert_share(cert_t *cert); -extern void cert_release(cert_t *cert); -extern void cert_list(bool utc); -extern cert_t* get_x509cert(identification_t *issuer, chunk_t keyid, cert_t* chain); - -#endif /* _CERTS_H */ - - diff --git a/src/pluto/connections.c b/src/pluto/connections.c deleted file mode 100644 index 27cec40fc..000000000 --- a/src/pluto/connections.c +++ /dev/null @@ -1,4507 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#include -#include "kameipsec.h" - -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "x509.h" -#include "ca.h" -#include "crl.h" -#include "certs.h" -#include "ac.h" -#include "smartcard.h" -#include "fetch.h" -#include "connections.h" -#include "foodgroups.h" -#include "demux.h" -#include "state.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "whack.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "whack_attribute.h" -#include "modecfg.h" - -static void flush_pending_by_connection(connection_t *c); /* forward */ - -static connection_t *connections = NULL; - -/* struct host_pair: a nexus of information about a pair of hosts. - * A host is an IP address, UDP port pair. This is a debatable choice: - * - should port be considered (no choice of port in standard)? - * - should ID be considered (hard because not always known)? - * - should IP address matter on our end (we don't know our end)? - * Only oriented connections are registered. - * Unoriented connections are kept on the unoriented_connections - * linked list (using hp_next). For them, host_pair is NULL. - */ - -struct host_pair { - struct { - ip_address addr; - u_int16_t port; /* host order */ - } me, him; - bool initial_connection_sent; - connection_t *connections; /* connections with this pair */ - struct pending *pending; /* awaiting Keying Channel */ - struct host_pair *next; -}; - -static struct host_pair *host_pairs = NULL; - -static connection_t *unoriented_connections = NULL; - -/** - * Check if an id was instantiated by assigning to it the current IP address - */ -bool his_id_was_instantiated(const connection_t *c) -{ - if (c->kind != CK_INSTANCE) - { - return FALSE; - } - if (id_is_ipaddr(c->spd.that.id)) - { - identification_t *host; - bool equal; - - host = identification_create_from_sockaddr((sockaddr_t*)&c->spd.that.host_addr); - equal = host->equals(host, c->spd.that.id); - host->destroy(host); - return equal; - } - else - { - return TRUE; - } -} - -/** - * Check to see that IDs of peers match - */ -bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id) -{ - return d->spd.this.id->equals(d->spd.this.id, c->spd.this.id) && - d->spd.that.id->equals(d->spd.that.id, - his_id ? his_id : c->spd.that.id); -} - -static struct host_pair *find_host_pair(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *p, *prev; - - /* default hisaddr to an appropriate any */ - if (hisaddr == NULL) - hisaddr = aftoinfo(addrtypeof(myaddr))->any; - - if (nat_traversal_enabled) - { - /** - * port is not relevant in host_pair. with nat_traversal we - * always use pluto_port (500) - */ - myport = pluto_port; - hisport = pluto_port; - } - - for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) - { - if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport - && sameaddr(&p->him.addr, hisaddr) && p->him.port == hisport) - { - if (prev) - { - prev->next = p->next; /* remove p from list */ - p->next = host_pairs; /* and stick it on front */ - host_pairs = p; - } - break; - } - } - return p; -} - -/* find head of list of connections with this pair of hosts */ -static connection_t *find_host_pair_connections(const ip_address *myaddr, - u_int16_t myport, - const ip_address *hisaddr, - u_int16_t hisport) -{ - struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); - - if (nat_traversal_enabled && hp && hisaddr) - { - connection_t *c; - - for (c = hp->connections; c != NULL; c = c->hp_next) - { - if (c->spd.this.host_port == myport && c->spd.that.host_port == hisport) - return c; - } - return NULL; - } - return hp == NULL? NULL : hp->connections; -} - -static void connect_to_host_pair(connection_t *c) -{ - if (oriented(*c)) - { - struct host_pair *hp; - - ip_address his_addr = (c->spd.that.allow_any) - ? *aftoinfo(addrtypeof(&c->spd.that.host_addr))->any - : c->spd.that.host_addr; - - hp = find_host_pair(&c->spd.this.host_addr, c->spd.this.host_port - , &his_addr, c->spd.that.host_port); - - if (hp == NULL) - { - /* no suitable host_pair -- build one */ - hp = malloc_thing(struct host_pair); - hp->me.addr = c->spd.this.host_addr; - hp->him.addr = his_addr; - hp->me.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port; - hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port; - hp->initial_connection_sent = FALSE; - hp->connections = NULL; - hp->pending = NULL; - hp->next = host_pairs; - host_pairs = hp; - } - c->host_pair = hp; - c->hp_next = hp->connections; - hp->connections = c; - } - else - { - /* since this connection isn't oriented, we place it - * in the unoriented_connections list instead. - */ - c->host_pair = NULL; - c->hp_next = unoriented_connections; - unoriented_connections = c; - } -} - -/* find a connection by name. - * If strict, don't accept a CK_INSTANCE. - * Move the winner (if any) to the front. - * If none is found, and strict, a diagnostic is logged to whack. - */ -connection_t *con_by_name(const char *nm, bool strict) -{ - connection_t *p, *prev; - - for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) - { - if (p == NULL) - { - if (strict) - whack_log(RC_UNKNOWN_NAME - , "no connection named \"%s\"", nm); - break; - } - if (streq(p->name, nm) - && (!strict || p->kind != CK_INSTANCE)) - { - if (prev) - { - prev->ac_next = p->ac_next; /* remove p from list */ - p->ac_next = connections; /* and stick it on front */ - connections = p; - } - break; - } - } - return p; -} - -void release_connection(connection_t *c, bool relations) -{ - if (c->kind == CK_INSTANCE) - { - /* This does everything we need. - * Note that we will be called recursively by delete_connection, - * but kind will be CK_GOING_AWAY. - */ - delete_connection(c, relations); - } - else - { - flush_pending_by_connection(c); - delete_states_by_connection(c, relations); - unroute_connection(c); - } -} - -/* Delete a connection */ - -#define list_rm(etype, enext, e, ehead) { \ - etype **ep; \ - for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \ - passert(*ep != NULL); /* we must not come up empty-handed */ \ - *ep = (e)->enext; \ - } - - -void delete_connection(connection_t *c, bool relations) -{ - modecfg_attribute_t *ca; - connection_t *old_cur_connection; - identification_t *client_id; - - old_cur_connection = cur_connection == c? NULL : cur_connection; -#ifdef DEBUG - lset_t old_cur_debugging = cur_debugging; -#endif - - set_cur_connection(c); - - /* Must be careful to avoid circularity: - * we mark c as going away so it won't get deleted recursively. - */ - passert(c->kind != CK_GOING_AWAY); - if (c->kind == CK_INSTANCE) - { - plog("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}" - , c->name - , ip_str(&c->spd.that.host_addr) - , c->newest_isakmp_sa, c->newest_ipsec_sa); - c->kind = CK_GOING_AWAY; - } - else - { - plog("deleting connection"); - } - release_connection(c, relations); /* won't delete c */ - - if (c->kind == CK_GROUP) - { - delete_group(c); - } - - /* free up any logging resources */ - perpeer_logfree(c); - - /* find and delete c from connections list */ - list_rm(connection_t, ac_next, c, connections); - cur_connection = old_cur_connection; - - /* find and delete c from the host pair list */ - if (c->host_pair == NULL) - { - if (c->ikev1) - { - list_rm(connection_t, hp_next, c, unoriented_connections); - } - } - else - { - struct host_pair *hp = c->host_pair; - - list_rm(connection_t, hp_next, c, hp->connections); - c->host_pair = NULL; /* redundant, but safe */ - - /* if there are no more connections with this host_pair - * and we haven't even made an initial contact, let's delete - * this guy in case we were created by an attempted DOS attack. - */ - if (hp->connections == NULL - && !hp->initial_connection_sent) - { - passert(hp->pending == NULL); /* ??? must deal with this! */ - list_rm(struct host_pair, next, hp, host_pairs); - free(hp); - } - } - if (c->kind != CK_GOING_AWAY) - { - free(c->spd.that.virt); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* release virtual IP address lease if any */ - if (c->spd.that.modecfg && c->spd.that.pool && - !c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - hydra->attributes->release_address(hydra->attributes, c->spd.that.pool, - c->spd.that.host_srcip, client_id); - } - - /* release requested attributes if any */ - if (c->requested) - { - c->requested->destroy_function(c->requested, - (void*)modecfg_attribute_destroy); - } - - /* release other attributes if any */ - if (c->attributes) - { - while (c->attributes->remove_last(c->attributes, (void **)&ca) == SUCCESS) - { - hydra->attributes->release(hydra->attributes, ca->handler, - client_id, ca->type, ca->value); - modecfg_attribute_destroy(ca); - } - c->attributes->destroy(c->attributes); - } - - if (c->kind != CK_GOING_AWAY) - { - whack_attr->del_pool(whack_attr, c->name); - } - - /* free internal data */ -#ifdef DEBUG - cur_debugging = old_cur_debugging; -#endif - free(c->name); - DESTROY_IF(c->xauth_identity); - DESTROY_IF(c->spd.this.id); - DESTROY_IF(c->spd.this.ca); - DESTROY_IF(c->spd.this.groups); - DESTROY_IF(c->spd.this.host_srcip); - free(c->spd.this.updown); - free(c->spd.this.pool); - DESTROY_IF(c->spd.that.id); - DESTROY_IF(c->spd.that.ca); - DESTROY_IF(c->spd.that.groups); - DESTROY_IF(c->spd.that.host_srcip); - free(c->spd.that.updown); - free(c->spd.that.pool); - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - } -#ifdef ADNS - gw_delref(&c->gw_info); -#endif - lock_certs_and_keys("delete_connection"); - cert_release(c->spd.this.cert); - scx_release(c->spd.this.sc); - cert_release(c->spd.that.cert); - scx_release(c->spd.that.sc); - unlock_certs_and_keys("delete_connection"); - - alg_info_delref((struct alg_info **)&c->alg_info_esp); - alg_info_delref((struct alg_info **)&c->alg_info_ike); - - free(c); -} - -/* Delete connections with the specified name */ -void delete_connections_by_name(const char *name, bool strict) -{ - connection_t *c = con_by_name(name, strict); - - for (; c != NULL; c = con_by_name(name, FALSE)) - delete_connection(c, FALSE); -} - -void delete_every_connection(void) -{ - while (connections) - { - delete_connection(connections, TRUE); - } -} - -void release_dead_interfaces(void) -{ - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - connection_t **pp - , *p; - - for (pp = &hp->connections; (p = *pp) != NULL; ) - { - if (p->interface->change == IFN_DELETE) - { - /* this connection's interface is going away */ - enum connection_kind k = p->kind; - - release_connection(p, TRUE); - - if (k <= CK_PERMANENT) - { - /* The connection should have survived release: - * move it to the unoriented_connections list. - */ - passert(p == *pp); - - p->interface = NULL; - - *pp = p->hp_next; /* advance *pp */ - p->host_pair = NULL; - p->hp_next = unoriented_connections; - unoriented_connections = p; - } - else - { - /* The connection should have vanished, - * but the previous connection remains. - */ - passert(p != *pp); - } - } - else - { - pp = &p->hp_next; /* advance pp */ - } - } - } -} - -/* adjust orientations of connections to reflect newly added interfaces */ -void check_orientations(void) -{ - /* try to orient all the unoriented connections */ - { - connection_t *c = unoriented_connections; - - unoriented_connections = NULL; - - while (c) - { - connection_t *nxt = c->hp_next; - - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - - /* Check that no oriented connection has become double-oriented. - * In other words, the far side must not match one of our new interfaces. - */ - { - struct iface *i; - - for (i = interfaces; i != NULL; i = i->next) - { - if (i->change == IFN_ADD) - { - struct host_pair *hp; - - for (hp = host_pairs; hp != NULL; hp = hp->next) - { - if (sameaddr(&hp->him.addr, &i->addr) - && hp->him.port == pluto_port) - { - /* bad news: the whole chain of connections - * hanging off this host pair has both sides - * matching an interface. - * We'll get rid of them, using orient and - * connect_to_host_pair. But we'll be lazy - * and not ditch the host_pair itself (the - * cost of leaving it is slight and cannot - * be induced by a foe). - */ - connection_t *c = hp->connections; - - hp->connections = NULL; - while (c) - { - connection_t *nxt = c->hp_next; - - c->interface = NULL; - (void)orient(c); - connect_to_host_pair(c); - c = nxt; - } - } - } - } - } - } -} - -static err_t default_end(struct end *e, ip_address *dflt_nexthop) -{ - err_t ugh = NULL; - int af = addrtypeof(&e->host_addr); - - if (af != AF_INET && af != AF_INET6) - { - return "unknown address family in default_end"; - } - - /* default ID to IP (but only if not NO_IP -- WildCard) */ - if (e->id->get_type(e->id) == ID_ANY && !isanyaddr(&e->host_addr)) - { - e->id->destroy(e->id); - e->id = identification_create_from_sockaddr((sockaddr_t*)&e->host_addr); - e->has_id_wildcards = FALSE; - } - - /* default nexthop to other side */ - if (isanyaddr(&e->host_nexthop)) - { - e->host_nexthop = *dflt_nexthop; - } - - /* default client to subnet containing only self - * XXX This may mean that the client's address family doesn't match - * tunnel_addr_family. - */ - if (!e->has_client) - { - ugh = addrtosubnet(&e->host_addr, &e->client); - } - return ugh; -} - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - * Returns strlen of formated result (length excludes NUL at end). - */ -size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy) -{ - char client[BUF_LEN]; - const char *client_sep = ""; - char protoport[sizeof(":255/65535")]; - const char *host = NULL; - char host_space[ADDRTOT_BUF]; - char host_port[sizeof(":65535")]; - char host_id[BUF_LEN + 2]; - char hop[ADDRTOT_BUF]; - const char *hop_sep = ""; - const char *open_brackets = ""; - const char *close_brackets = ""; - - if (isanyaddr(&this->host_addr)) - { - switch (policy & (POLICY_GROUP | POLICY_OPPO)) - { - case POLICY_GROUP: - host = "%group"; - break; - case POLICY_OPPO: - host = "%opportunistic"; - break; - case POLICY_GROUP | POLICY_OPPO: - host = "%opportunisticgroup"; - break; - default: - host = "%any"; - break; - } - } - - client[0] = '\0'; - - if (is_virtual_end(this) && isanyaddr(&this->host_addr)) - { - host = "%virtual"; - } - - /* [client===] */ - if (this->has_client) - { - ip_address client_net, client_mask; - - networkof(&this->client, &client_net); - maskof(&this->client, &client_mask); - client_sep = "==="; - - /* {client_subnet_wildcard} */ - if (this->has_client_wildcard) - { - open_brackets = "{"; - close_brackets = "}"; - } - - if (isanyaddr(&client_net) && isanyaddr(&client_mask) - && (policy & (POLICY_GROUP | POLICY_OPPO))) - { - client_sep = ""; /* boring case */ - } - else if (subnetisnone(&this->client)) - { - strncpy(client, "?", sizeof(client)); - } - else - { - subnettot(&this->client, 0, client, sizeof(client)); - } - } - else if (this->modecfg && this->host_srcip->is_anyaddr(this->host_srcip)) - { - /* we are mode config client, or a server with a pool */ - client_sep = "==="; - client[0] = '%'; - strncpy(client+1, this->pool ?: "modecfg", sizeof(client)-1); - } - - /* host */ - if (host == NULL) - { - addrtot(&this->host_addr, 0, host_space, sizeof(host_space)); - host = host_space; - } - - host_port[0] = '\0'; - if (this->host_port != IKE_UDP_PORT) - { - snprintf(host_port, sizeof(host_port), ":%u", this->host_port); - } - - /* payload portocol and port */ - protoport[0] = '\0'; - if (this->has_port_wildcard) - { - snprintf(protoport, sizeof(protoport), ":%u/%%any", this->protocol); - } - else if (this->port || this->protocol) - { - snprintf(protoport, sizeof(protoport), ":%u/%u", this->protocol - , this->port); - } - - /* id */ - snprintf(host_id, sizeof(host_id), "[%Y]", this->id); - - /* [---hop] */ - hop[0] = '\0'; - hop_sep = ""; - if (that && !sameaddr(&this->host_nexthop, &that->host_addr)) - { - addrtot(&this->host_nexthop, 0, hop, sizeof(hop)); - hop_sep = "---"; - } - - if (is_left) - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , open_brackets, client, close_brackets, client_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport - , hop_sep, hop); - } - else - { - snprintf(buf, buf_len, "%s%s%s%s%s%s%s%s%s%s%s" - , hop, hop_sep - , this->allow_any? "%":"" - , host, host_port, host_id, protoport, client_sep - , open_brackets, client, close_brackets); - } - return strlen(buf); -} - -/* format topology of a connection. - * Two symmetric ends separated by ... - */ -#define CONNECTION_BUF (2 * (END_BUF - 1) + 4) - -static size_t format_connection(char *buf, size_t buf_len, - const connection_t *c, - struct spd_route *sr) -{ - size_t w = format_end(buf, buf_len, &sr->this, &sr->that, TRUE, LEMPTY); - - w += snprintf(buf + w, buf_len - w, "..."); - return w + format_end(buf + w, buf_len - w, &sr->that, &sr->this, FALSE, c->policy); -} - -static void unshare_connection_strings(connection_t *c) -{ - c->name = clone_str(c->name); - if (c->xauth_identity) - { - c->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - c->spd.this.id = c->spd.this.id->clone(c->spd.this.id); - c->spd.this.pool = clone_str(c->spd.this.pool); - c->spd.this.updown = clone_str(c->spd.this.updown); - c->spd.this.host_srcip = c->spd.this.host_srcip->clone(c->spd.this.host_srcip); - scx_share(c->spd.this.sc); - cert_share(c->spd.this.cert); - if (c->spd.this.ca) - { - c->spd.this.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - if (c->spd.this.groups) - { - c->spd.this.groups = c->spd.this.groups->get_ref(c->spd.this.groups); - } - c->spd.that.id = c->spd.that.id->clone(c->spd.that.id); - c->spd.that.pool = clone_str(c->spd.that.pool); - c->spd.that.updown = clone_str(c->spd.that.updown); - c->spd.that.host_srcip = c->spd.that.host_srcip->clone(c->spd.that.host_srcip); - scx_share(c->spd.that.sc); - cert_share(c->spd.that.cert); - if (c->spd.that.ca) - { - c->spd.that.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - if (c->spd.that.groups) - { - c->spd.that.groups = c->spd.that.groups->get_ref(c->spd.that.groups); - } - - /* increment references to algo's */ - alg_info_addref((struct alg_info *)c->alg_info_esp); - alg_info_addref((struct alg_info *)c->alg_info_ike); -} - -static void load_end_certificate(char *filename, struct end *dst) -{ - time_t notBefore, notAfter; - cert_t *cert = NULL; - certificate_t *certificate; - bool cached_cert = FALSE; - - /* initialize end certificate */ - dst->cert = NULL; - - /* initialize smartcard info record */ - dst->sc = NULL; - - if (filename) - { - if (scx_on_smartcard(filename)) - { - /* load cert from smartcard */ - cert = scx_load_cert(filename, &dst->sc, &cached_cert); - } - else - { - /* load cert from file */ - cert = load_host_cert(filename); - } - } - - if (cert) - { - certificate = cert->cert; - - if (dst->id->get_type(dst->id) == ID_ANY || - !certificate->has_subject(certificate, dst->id)) - { - plog( " id '%Y' not confirmed by certificate, defaulting to '%Y'", - dst->id, certificate->get_subject(certificate)); - dst->id->destroy(dst->id); - dst->id = certificate->get_subject(certificate); - dst->id = dst->id->clone(dst->id); - } - - if (cached_cert) - { - dst->cert = cert; - } - else - { - if (!certificate->get_validity(certificate, NULL, ¬Before, ¬After)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬Before, FALSE, ¬After, FALSE); - cert_free(cert); - return; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - add_public_key_from_cert(cert, notAfter, DAL_LOCAL); - dst->cert = cert_add(cert); - } - certificate = dst->cert->cert; - - /* if no CA is defined, use issuer as default */ - if (dst->ca == NULL && certificate->get_type(certificate) == CERT_X509) - { - identification_t *issuer; - - issuer = certificate->get_issuer(certificate); - dst->ca = issuer->clone(issuer); - } - - /* cache the certificate that was last retrieved from the smartcard */ - if (dst->sc) - { - if (!dst->sc->last_cert || - !certificate->equals(certificate, dst->sc->last_cert->cert)) - { - lock_certs_and_keys("load_end_certificates"); - cert_release(dst->sc->last_cert); - dst->sc->last_cert = dst->cert; - cert_share(dst->cert); - unlock_certs_and_keys("load_end_certificates"); - } - time(&dst->sc->last_load); - } - } - scx_share(dst->sc); - cert_share(dst->cert); -} - -static bool extract_end(struct end *dst, const whack_end_t *src, - const char *name, bool is_left) -{ - bool same_ca = FALSE; - - dst->is_left = is_left; - dst->id = identification_create_from_string(src->id); - dst->ca = NULL; - - /* decode CA distinguished name, if any */ - if (src->ca) - { - if streq(src->ca, "%same") - { - same_ca = TRUE; - } - else if (!streq(src->ca, "%any")) - { - dst->ca = identification_create_from_string(src->ca); - if (dst->ca->get_type(dst->ca) != ID_DER_ASN1_DN) - { - plog("bad CA string '%s', ignored", src->ca); - dst->ca->destroy(dst->ca); - dst->ca = NULL; - } - } - } - - /* load local end certificate and extract ID, if any */ - load_end_certificate(src->cert, dst); - - /* does id has wildcards? */ - dst->has_id_wildcards = dst->id->contains_wildcards(dst->id); - - /* decode group attributes, if any */ - if (src->groups) - { - dst->groups = ietf_attributes_create_from_string(src->groups); - } - - /* the rest is simple copying of corresponding fields */ - dst->host_addr = src->host_addr; - dst->host_nexthop = src->host_nexthop; - dst->host_srcip = host_create_from_sockaddr((sockaddr_t*)&src->host_srcip); - dst->has_natip = src->has_natip; - dst->client = src->client; - dst->protocol = src->protocol; - dst->port = src->port; - dst->has_port_wildcard = src->has_port_wildcard; - dst->key_from_DNS_on_demand = src->key_from_DNS_on_demand; - dst->has_client = src->has_client; - dst->has_client_wildcard = src->has_client_wildcard; - dst->modecfg = src->modecfg; - dst->hostaccess = src->hostaccess; - dst->allow_any = src->allow_any; - dst->sendcert = src->sendcert; - dst->updown = clone_str(src->updown); - dst->host_port = src->host_port; - - /* if the sourceip netmask is zero a named pool exists */ - if (src->sourceip_mask == 0) - { - dst->pool = clone_str(src->sourceip); - } - - /* if host sourceip is defined but no client is present - * behind the host then set client to sourceip/32 - */ - if (!dst->host_srcip->is_anyaddr(dst->host_srcip) && - !dst->has_natip && !dst->has_client) - { - ip_address addr; - err_t ugh; - - addr = *(ip_address*)dst->host_srcip->get_sockaddr(dst->host_srcip); - ugh = addrtosubnet(&addr, &dst->client); - - if (ugh) - { - plog("could not assign host sourceip to client subnet"); - } - else - { - dst->has_client = TRUE; - } - } - return same_ca; -} - -static bool check_connection_end(const whack_end_t *this, - const whack_end_t *that, - const whack_message_t *wm) -{ - if (wm->addr_family != addrtypeof(&this->host_addr) - || wm->addr_family != addrtypeof(&this->host_nexthop) - || (this->has_client? wm->tunnel_addr_family : wm->addr_family) - != subnettypeof(&this->client) - || subnettypeof(&this->client) != subnettypeof(&that->client)) - { - /* this should have been diagnosed by whack, so we need not be clear - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "address family inconsistency in connection"); - return FALSE; - } - - if (isanyaddr(&that->host_addr)) - { - /* other side is wildcard: we must check if other conditions met */ - if (isanyaddr(&this->host_addr)) - { - loglog(RC_ORIENT, "connection must specify host IP address for our side"); - return FALSE; - } - } - - if (this->virt && (!isanyaddr(&this->host_addr) || this->has_client)) - { - loglog(RC_CLASH, - "virtual IP must only be used with %%any and without client"); - return FALSE; - } - - return TRUE; /* happy */ -} - -connection_t *find_connection_by_reqid(uint32_t reqid) -{ - connection_t *c; - - reqid &= ~3; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->spd.reqid == reqid) - { - return c; - } - } - - return NULL; -} - -static uint32_t gen_reqid(void) -{ - uint32_t start; - static uint32_t reqid = IPSEC_MANUAL_REQID_MAX & ~3; - - start = reqid; - do { - reqid += 4; - if (reqid == 0) - { - reqid = (IPSEC_MANUAL_REQID_MAX & ~3) + 4; - } - if (!find_connection_by_reqid(reqid)) - { - return reqid; - } - } while (reqid != start); - - exit_log("unable to allocate reqid"); - return 0; /* never reached ... */ -} - -void add_connection(const whack_message_t *wm) -{ - if (con_by_name(wm->name, FALSE) != NULL) - { - loglog(RC_DUPNAME, "attempt to redefine connection \"%s\"", wm->name); - } - else if (wm->right.protocol != wm->left.protocol) - { - /* this should haven been diagnosed by whack - * !!! overloaded use of RC_CLASH - */ - loglog(RC_CLASH, "the protocol must be the same for leftport and rightport"); - } - else if (check_connection_end(&wm->right, &wm->left, wm) - && check_connection_end(&wm->left, &wm->right, wm)) - { - bool same_rightca, same_leftca; - connection_t *c = malloc_thing(connection_t); - - zero(c); - c->name = clone_str(wm->name); - c->ikev1 = wm->ikev1; - c->policy = wm->policy; - - if ((c->policy & POLICY_COMPRESS) && !can_do_IPcomp) - { - loglog(RC_COMMENT - , "ignoring --compress in \"%s\" because kernel does not support IPCOMP" - , c->name); - } - - if (wm->esp) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --esp=%s", wm->esp ? wm->esp: "NULL") - ) - c->alg_info_esp = alg_info_esp_create_from_str(wm->esp? wm->esp : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]=""; - - if (c->alg_info_esp) - { - alg_info_snprint(buf, sizeof(buf) - ,(struct alg_info *)c->alg_info_esp); - } - DBG_log("esp proposal: %s", buf); - ) - if (c->alg_info_esp) - { - if (c->alg_info_esp->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 esp transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in esp string"); - } - } - - if (wm->ike) - { - DBG(DBG_CONTROL, - DBG_log("from whack: got --ike=%s", wm->ike ? wm->ike: "NULL") - ) - c->alg_info_ike= alg_info_ike_create_from_str(wm->ike? wm->ike : ""); - - DBG(DBG_CRYPT|DBG_CONTROL, - static char buf[BUF_LEN]=""; - - if (c->alg_info_ike) - { - alg_info_snprint(buf, sizeof(buf) - , (struct alg_info *)c->alg_info_ike); - } - DBG_log("ike proposal: %s", buf); - ) - if (c->alg_info_ike) - { - if (c->alg_info_ike->alg_info_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "got 0 ike transforms"); - } - } - else - { - loglog(RC_LOG_SERIOUS, "syntax error in ike string"); - } - } - - if (wm->xauth_identity) - { - c->xauth_identity - = identification_create_from_string(wm->xauth_identity); - } - - c->sa_ike_life_seconds = wm->sa_ike_life_seconds; - c->sa_ipsec_life_seconds = wm->sa_ipsec_life_seconds; - c->sa_rekey_margin = wm->sa_rekey_margin; - c->sa_rekey_fuzz = wm->sa_rekey_fuzz; - c->sa_keying_tries = wm->sa_keying_tries; - - /* RFC 3706 DPD */ - c->dpd_delay = wm->dpd_delay; - c->dpd_timeout = wm->dpd_timeout; - c->dpd_action = wm->dpd_action; - - c->addr_family = wm->addr_family; - c->tunnel_addr_family = wm->tunnel_addr_family; - - c->requested_ca = NULL; - same_leftca = extract_end(&c->spd.this, &wm->left, wm->name, TRUE); - same_rightca = extract_end(&c->spd.that, &wm->right, wm->name, FALSE); - - if (same_rightca && c->spd.this.ca) - { - c->spd.that.ca = c->spd.this.ca->clone(c->spd.this.ca); - } - else if (same_leftca && c->spd.that.ca) - { - c->spd.this.ca = c->spd.that.ca->clone(c->spd.that.ca); - } - - default_end(&c->spd.this, &c->spd.that.host_addr); - default_end(&c->spd.that, &c->spd.this.host_addr); - - /* force any wildcard host IP address, any wildcard subnet - * or any wildcard ID to that end - */ - if (isanyaddr(&c->spd.this.host_addr) || c->spd.this.has_client_wildcard - || c->spd.this.has_port_wildcard || c->spd.this.has_id_wildcards - || c->spd.this.allow_any) - { - struct end t = c->spd.this; - - c->spd.this = c->spd.that; - c->spd.that = t; - } - - c->spd.next = NULL; - c->spd.reqid = wm->reqid ?: gen_reqid(); - - c->spd.mark_in.value = wm->mark_in.value; - c->spd.mark_in.mask = wm->mark_in.mask; - c->spd.mark_out.value = wm->mark_out.value; - c->spd.mark_out.mask = wm->mark_out.mask; - - /* set internal fields */ - c->instance_serial = 0; - c->ac_next = connections; - connections = c; - c->interface = NULL; - c->spd.routing = RT_UNROUTED; - c->newest_isakmp_sa = SOS_NOBODY; - c->newest_ipsec_sa = SOS_NOBODY; - c->spd.eroute_owner = SOS_NOBODY; - - if (c->policy & POLICY_GROUP) - { - c->kind = CK_GROUP; - add_group(c); - } - else if ((isanyaddr(&c->spd.that.host_addr) && !NEVER_NEGOTIATE(c->policy)) - || c->spd.that.has_client_wildcard || c->spd.that.has_port_wildcard - || c->spd.that.has_id_wildcards || c->spd.that.allow_any) - { - /* Opportunistic or Road Warrior or wildcard client subnet - * or wildcard ID */ - c->kind = CK_TEMPLATE; - } - else - { - c->kind = CK_PERMANENT; - } - set_policy_prio(c); /* must be after kind is set */ - -#ifdef DEBUG - c->extra_debugging = wm->debugging; -#endif - - c->gw_info = NULL; - - passert(!(wm->left.virt && wm->right.virt)); - if (wm->left.virt || wm->right.virt) - { - passert(isanyaddr(&c->spd.that.host_addr)); - c->spd.that.virt = create_virtual(c, - wm->left.virt ? wm->left.virt : wm->right.virt); - if (c->spd.that.virt) - c->spd.that.has_client = TRUE; - } - - (void)orient(c); - - /* if rightsourceip defines a subnet then create an in-memory pool */ - if (whack_attr->add_pool(whack_attr, c->name, - c->spd.this.is_left ? &wm->right : &wm->left)) - { - c->spd.that.pool = clone_str(c->name); - c->spd.that.modecfg = TRUE; - c->spd.that.has_client = FALSE; - /* reset the host_srcip so that it gets assigned in modecfg */ - DESTROY_IF(c->spd.that.host_srcip); - c->spd.that.host_srcip = host_create_any(AF_INET); - } - - if (c->ikev1) - { - connect_to_host_pair(c); - } - - /* log all about this connection */ - plog("added connection description \"%s\"", c->name); - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), c, &c->spd); - - DBG_log("%s", topo); - - /* Make sure that address families can be correctly inferred - * from printed ends. - */ - passert(c->addr_family == addrtypeof(&c->spd.this.host_addr) - && c->addr_family == addrtypeof(&c->spd.this.host_nexthop) - && (c->spd.this.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.this.client) - - && c->addr_family == addrtypeof(&c->spd.that.host_addr) - && c->addr_family == addrtypeof(&c->spd.that.host_nexthop) - && (c->spd.that.has_client? c->tunnel_addr_family : c->addr_family) - == subnettypeof(&c->spd.that.client)); - - DBG_log("ike_life: %lus; ipsec_life: %lus; rekey_margin: %lus;" - " rekey_fuzz: %lu%%; keyingtries: %lu; policy: %s" - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries - , prettypolicy(c->policy)); - ); - } -} - -/* Derive a template connection from a group connection and target. - * Similar to instantiate(). Happens at whack --listen. - * Returns name of new connection. May be NULL. - * Caller is responsible for freeing. - */ -char *add_group_instance(connection_t *group, const ip_subnet *target) -{ - char namebuf[100], targetbuf[SUBNETTOT_BUF]; - connection_t *t; - char *name = NULL; - - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - /* manufacture a unique name for this template */ - subnettot(target, 0, targetbuf, sizeof(targetbuf)); - snprintf(namebuf, sizeof(namebuf), "%s#%s", group->name, targetbuf); - - if (con_by_name(namebuf, FALSE) != NULL) - { - loglog(RC_DUPNAME, "group name + target yields duplicate name \"%s\"" - , namebuf); - } - else - { - t = clone_thing(*group); - t->name = namebuf; - unshare_connection_strings(t); - name = clone_str(t->name); - t->spd.that.client = *target; - t->policy &= ~(POLICY_GROUP | POLICY_GROUTED); - t->kind = isanyaddr(&t->spd.that.host_addr) && !NEVER_NEGOTIATE(t->policy) - ? CK_TEMPLATE : CK_INSTANCE; - - /* reset log file info */ - t->log_file_name = NULL; - t->log_file = NULL; - t->log_file_err = FALSE; - - t->spd.reqid = gen_reqid(); - - if (t->spd.that.virt) - { - DBG_log("virtual_ip not supported in group instance"); - t->spd.that.virt = NULL; - } - - /* add to connections list */ - t->ac_next = connections; - connections = t; - - /* same host_pair as parent: stick after parent on list */ - group->hp_next = t; - - /* route if group is routed */ - if (group->policy & POLICY_GROUTED) - { - if (!trap_connection(t)) - whack_log(RC_ROUTE, "could not route"); - } - } - return name; -} - -/* an old target has disappeared for a group: delete instance */ -void remove_group_instance(const connection_t *group USED_BY_DEBUG, - const char *name) -{ - passert(group->kind == CK_GROUP); - passert(oriented(*group)); - - delete_connections_by_name(name, FALSE); -} - -/* Common part of instantiating a Road Warrior or Opportunistic connection. - * his_id can be used to carry over an ID discovered in Phase 1. - * It must not disagree with the one in c, but if that is unspecified, - * the new connection will use his_id. - * If his_id is NULL, and c.that.id is uninstantiated (ID_ANY), the - * new connection will continue to have an uninstantiated that.id. - * Note: instantiation does not affect port numbers. - * - * Note that instantiate can only deal with a single SPD/eroute. - */ -static connection_t *instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, identification_t *his_id) -{ - connection_t *d; - - passert(c->kind == CK_TEMPLATE); - passert(c->spd.next == NULL); - - c->instance_serial++; - d = clone_thing(*c); - d->spd.that.allow_any = FALSE; - - if (his_id) - { - d->spd.that.id = his_id; - d->spd.that.has_id_wildcards = FALSE; - } - unshare_connection_strings(d); - if (d->spd.this.groups) - { - d->spd.this.groups = d->spd.this.groups->get_ref(d->spd.this.groups); - } - if (d->spd.that.groups) - { - d->spd.that.groups = d->spd.that.groups->get_ref(d->spd.that.groups); - } - d->kind = CK_INSTANCE; - - passert(oriented(*d)); - d->spd.that.host_addr = *him; - setportof(htons(c->spd.that.port), &d->spd.that.host_addr); - - if (his_port) d->spd.that.host_port = his_port; - - default_end(&d->spd.that, &d->spd.this.host_addr); - - /* We cannot guess what our next_hop should be, but if it was - * explicitly specified as 0.0.0.0, we set it to be him. - * (whack will not allow nexthop to be elided in RW case.) - */ - default_end(&d->spd.this, &d->spd.that.host_addr); - d->spd.next = NULL; - d->spd.reqid = gen_reqid(); - - /* set internal fields */ - d->ac_next = connections; - connections = d; - d->spd.routing = RT_UNROUTED; - d->newest_isakmp_sa = SOS_NOBODY; - d->newest_ipsec_sa = SOS_NOBODY; - d->spd.eroute_owner = SOS_NOBODY; - - /* reset log file info */ - d->log_file_name = NULL; - d->log_file = NULL; - d->log_file_err = FALSE; - - connect_to_host_pair(d); - - if (sameaddr(&d->spd.that.host_addr, &d->spd.this.host_nexthop)) - { - d->spd.this.host_nexthop = *him; - } - return d; -} - -connection_t *rw_instantiate(connection_t *c, const ip_address *him, - u_int16_t his_port, const ip_subnet *his_net, - identification_t *his_id) -{ - connection_t *d = instantiate(c, him, his_port, his_id); - - if (d && his_net && is_virtual_connection(c)) - { - d->spd.that.client = *his_net; - d->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(him, his_net)) - d->spd.that.has_client = FALSE; - } - - if (d->policy & POLICY_OPPO) - { - /* This must be before we know the client addresses. - * Fill in one that is impossible. This prevents anyone else from - * trying to use this connection to get to a particular client - */ - d->spd.that.client = *aftoinfo(subnettypeof(&d->spd.that.client))->none; - } - DBG(DBG_CONTROL - , DBG_log("instantiated \"%s\" for %s" , d->name, ip_str(him))); - return d; -} - -#ifdef ADNS - -connection_t *oppo_instantiate(connection_t *c, const ip_address *him, - identification_t *his_id, struct gw_info *gw, - const ip_address *our_client USED_BY_DEBUG, - const ip_address *peer_client) -{ - connection_t *d = instantiate(c, him, 0, his_id); - - passert(d->spd.next == NULL); - - /* fill in our client side */ - if (d->spd.this.has_client) - { - /* there was a client in the abstract connection - * so we demand that the required client is within that subnet. - */ - passert(addrinsubnet(our_client, &d->spd.this.client)); - happy(addrtosubnet(our_client, &d->spd.this.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.this.client.addr); - } - else - { - /* there was no client in the abstract connection - * so we demand that the required client be the host - */ - passert(sameaddr(our_client, &d->spd.this.host_addr)); - } - - /* fill in peer's client side. - * If the client is the peer, excise the client from the connection. - */ - passert((d->policy & POLICY_OPPO) - && addrinsubnet(peer_client, &d->spd.that.client)); - happy(addrtosubnet(peer_client, &d->spd.that.client)); - /* opportunistic connections do not use port selectors */ - setportof(0, &d->spd.that.client.addr); - - if (sameaddr(peer_client, &d->spd.that.host_addr)) - d->spd.that.has_client = FALSE; - - passert(d->gw_info == NULL); - gw_addref(gw); - d->gw_info = gw; - - /* Adjust routing if something is eclipsing c. - * It must be a %hold for us (hard to passert this). - * If there was another instance eclipsing, we'd be using it. - */ - if (c->spd.routing == RT_ROUTED_ECLIPSED) - d->spd.routing = RT_ROUTED_PROSPECTIVE; - - /* Remember if the template is routed: - * if so, this instance applies for initiation - * even if it is created for responding. - */ - if (routed(c->spd.routing)) - d->instance_initiation_ok = TRUE; - - DBG(DBG_CONTROL, - char topo[BUF_LEN]; - - (void) format_connection(topo, sizeof(topo), d, &d->spd); - DBG_log("instantiated \"%s\": %s", d->name, topo); - ); - return d; -} - -#endif /* ADNS */ - -/* priority formatting */ -void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]) -{ - if (pp == BOTTOM_PRIO) - { - snprintf(buf, POLICY_PRIO_BUF, "0"); - } - else - { - snprintf(buf, POLICY_PRIO_BUF, "%lu,%lu" - , pp>>16, (pp & ~(~(policy_prio_t)0 << 16)) >> 8); - } -} - -/* Format any information needed to identify an instance of a connection. - * Fills any needed information into buf which MUST be big enough. - * Road Warrior: peer's IP address - * Opportunistic: [" " myclient "==="] " ..." peer ["===" hisclient] '\0' - */ -static size_t fmt_client(const ip_subnet *client, const ip_address *gw, - const char *prefix, char buf[ADDRTOT_BUF]) -{ - if (subnetisaddr(client, gw)) - { - buf[0] = '\0'; /* compact denotation for "self" */ - } - else - { - char *ap; - - strcpy(buf, prefix); - ap = buf + strlen(prefix); - if (subnetisnone(client)) - strcpy(ap, "?"); /* unknown */ - else - subnettot(client, 0, ap, SUBNETTOT_BUF); - } - return strlen(buf); -} - -void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]) -{ - char *p = buf; - - *p = '\0'; - - if (c->kind == CK_INSTANCE) - { - if (c->instance_serial != 0) - { - snprintf(p, CONN_INST_BUF, "[%lu]", c->instance_serial); - p += strlen(p); - } - - if (c->policy & POLICY_OPPO) - { - size_t w = fmt_client(&c->spd.this.client, &c->spd.this.host_addr, " ", p); - - p += w; - - strcpy(p, w == 0? " ..." : "=== ..."); - p += strlen(p); - - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); - p += strlen(p); - - (void) fmt_client(&c->spd.that.client, &c->spd.that.host_addr, "===", p); - } - else - { - *p++ = ' '; - addrtot(&c->spd.that.host_addr, 0, p, ADDRTOT_BUF); -# - if (c->spd.that.host_port != pluto_port) - { - p += strlen(p); - sprintf(p, ":%d", c->spd.that.host_port); - } - } - } -} - -/* Find an existing connection for a trapped outbound packet. - * This is attempted before we bother with gateway discovery. - * + this connection is routed or instance_of_routed_template - * (i.e. approved for on-demand) - * + this subnet contains our_client (or we are our_client) - * + that subnet contains peer_client (or peer is peer_client) - * + don't care about Phase 1 IDs (we don't know) - * Note: result may still need to be instantiated. - * The winner has the highest policy priority. - * - * If there are several with that priority, we give preference to - * the first one that is an instance. - * - * See also build_outgoing_opportunistic_connection. - */ -connection_t *find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto) -{ - connection_t *c = connections, *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - struct spd_route *sr; - struct spd_route *best_sr = NULL; - int our_port = ntohs(portof(our_client)); - int peer_port = ntohs(portof(peer_client)); - - passert(!isanyaddr(our_client) && !isanyaddr(peer_client)); -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - DBG_log("find_connection: " - "looking for policy for connection: %s:%d/%d -> %s:%d/%d" - , ocb, transport_proto, our_port, pcb, transport_proto, peer_port); - } -#endif /* DEBUG */ - - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if ((routed(sr->routing) || c->instance_initiation_ok) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client) - && addrinsubnet(peer_client, &sr->that.client) - && (!sr->this.protocol || transport_proto == sr->this.protocol) - && (!sr->this.port || our_port == sr->this.port) - && (!sr->that.port || peer_port == sr->that.port)) - { - char cib[CONN_INST_BUF]; - char cib2[CONN_INST_BUF]; - - policy_prio_t prio = 8 * (c->prio + (c->kind == CK_INSTANCE)) - + 2 * (sr->this.port == our_port) - + 2 * (sr->that.port == peer_port) - + (sr->this.protocol == transport_proto); - -#ifdef DEBUG - if (DBGP(DBG_CONTROL|DBG_CONTROLMORE)) - { - char c_ocb[SUBNETTOT_BUF], c_pcb[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, c_ocb, sizeof(c_ocb)); - subnettot(&c->spd.that.client, 0, c_pcb, sizeof(c_pcb)); - DBG_log("find_connection: conn \"%s\"%s has compatible peers: %s->%s [pri: %ld]" - , c->name - , (fmt_conn_instance(c, cib), cib) - , c_ocb, c_pcb, prio); - } -#endif /* DEBUG */ - - if (best == NULL) - { - best = c; - best_sr = sr; - best_prio = prio; - } - - DBG(DBG_CONTROLMORE, - DBG_log("find_connection: " - "comparing best \"%s\"%s [pri:%ld]{%p} (child %s) to \"%s\"%s [pri:%ld]{%p} (child %s)" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , (best->policy_next ? best->policy_next->name : "none") - , c->name - , (fmt_conn_instance(c, cib2), cib2) - , prio - , c - , (c->policy_next ? c->policy_next->name : "none"))); - - if (prio > best_prio) - { - best = c; - best_sr = sr; - best_prio = prio; - } - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - if (srp && best) - { - *srp = best_sr; - } - -#ifdef DEBUG - if (DBGP(DBG_CONTROL)) - { - if (best) - { - char cib[CONN_INST_BUF]; - DBG_log("find_connection: concluding with \"%s\"%s [pri:%ld]{%p} kind=%s" - , best->name - , (fmt_conn_instance(best, cib), cib) - , best_prio - , best - , enum_name(&connection_kind_names, best->kind)); - } else { - DBG_log("find_connection: concluding with empty"); - } - } -#endif /* DEBUG */ - - return best; -} - -#ifdef ADNS - -/* Find and instantiate a connection for an outgoing Opportunistic connection. - * We've already discovered its gateway. - * We look for a the connection such that: - * + this is one of our interfaces - * + this subnet contains our_client (or we are our_client) - * (we will specialize the client). We prefer the smallest such subnet. - * + that subnet contains peer_clent (we will specialize the client). - * We prefer the smallest such subnet. - * + is opportunistic - * + that peer is NO_IP - * + don't care about Phase 1 IDs (probably should be default) - * We could look for a connection that already had the desired peer - * (rather than NO_IP) specified, but it doesn't seem worth the - * bother. - * - * We look for the routed policy applying to the narrowest subnets. - * We only succeed if we find such a policy AND it is satisfactory. - * - * The body of the inner loop is a lot like that in - * find_connection_for_clients. In this case, we know the gateways - * that we need to instantiate an opportunistic connection. - */ -connection_t *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client) -{ - struct iface *p; - connection_t *best = NULL; - struct spd_route *sr, *bestsr; - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(our_client, 0, ocb, sizeof(ocb)); - addrtot(peer_client, 0, pcb, sizeof(pcb)); - - /* for each of our addresses... */ - for (p = interfaces; p != NULL; p = p->next) - { - /* go through those connections with our address and NO_IP as hosts - * We cannot know what port the peer would use, so we assume - * that it is pluto_port (makes debugging easier). - */ - connection_t *c = find_host_pair_connections(&p->addr, pluto_port, - (ip_address *)NULL, pluto_port); - - for (; c != NULL; c = c->hp_next) - { - DBG(DBG_OPPO, - DBG_log("checking %s", c->name)); - if (c->kind == CK_GROUP) - { - continue; - } - - for (sr = &c->spd; best!=c && sr; sr = sr->next) - { - if (routed(sr->routing) - && addrinsubnet(our_client, &sr->this.client) - && addrinsubnet(peer_client, &sr->that.client)) - { - if (best == NULL) - { - best = c; - break; - } - - DBG(DBG_OPPO, - DBG_log("comparing best %s to %s" - , best->name, c->name)); - - for (bestsr = &best->spd; best!=c && bestsr; bestsr=bestsr->next) - { - if (!subnetinsubnet(&bestsr->this.client, &sr->this.client) - || (samesubnet(&bestsr->this.client, &sr->this.client) - && !subnetinsubnet(&bestsr->that.client - , &sr->that.client))) - { - best = c; - } - } - } - } - } - } - - if (best == NULL || NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY || best->kind != CK_TEMPLATE) - { - return NULL; - } - else - { - chunk_t encoding = gw->gw_id->get_encoding(gw->gw_id); - id_type_t type = gw->gw_id->get_type(gw->gw_id); - ip_address ip_addr; - - initaddr(encoding.ptr, encoding.len, - (type == ID_IPV4_ADDR) ? AF_INET : AF_INET6, &ip_addr); - - return oppo_instantiate(best, &ip_addr, NULL, gw, our_client, peer_client); - } -} - -#endif /* ADNS */ - -bool orient(connection_t *c) -{ - struct spd_route *sr; - - if (!oriented(*c)) - { - struct iface *p; - - for (sr = &c->spd; sr; sr = sr->next) - { - /* Note: this loop does not stop when it finds a match: - * it continues checking to catch any ambiguity. - */ - for (p = interfaces; p != NULL; p = p->next) - { - if (p->ike_float) - { - continue; - } - - for (;;) - { - /* check if this interface matches this end */ - if (sameaddr(&sr->this.host_addr, &p->addr) - && sr->this.host_port == pluto_port) - { - if (oriented(*c)) - { - if (c->interface == p) - loglog(RC_LOG_SERIOUS - , "both sides of \"%s\" are our interface %s!" - , c->name, p->rname); - else - loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)" - , c->name, c->interface->rname, p->rname); - c->interface = NULL; /* withdraw orientation */ - return FALSE; - } - c->interface = p; - } - - /* done with this interface if it doesn't match that end */ - if (!(sameaddr(&sr->that.host_addr, &p->addr) - && sr->that.host_port == pluto_port)) - break; - - /* swap ends and try again. - * It is a little tricky to see that this loop will stop. - * Only continue if the far side matches. - * If both sides match, there is an error-out. - */ - { - struct end t = sr->this; - - sr->this = sr->that; - sr->that = t; - } - } - } - } - } - return oriented(*c); -} - -void initiate_connection(const char *name, int whackfd) -{ - connection_t *c = con_by_name(name, TRUE); - - if (c && c->ikev1) - { - set_cur_connection(c); - if (!oriented(*c)) - { - loglog(RC_ORIENT, "we have no ipsecN interface for either end of this connection"); - } - else if (NEVER_NEGOTIATE(c->policy)) - { - loglog(RC_INITSHUNT - , "cannot initiate an authby=never connection"); - } - else if (c->kind != CK_PERMANENT && !c->spd.that.allow_any) - { - if (isanyaddr(&c->spd.that.host_addr)) - loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address"); - else - loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards"); - } - else - { - /* do we have to prompt for a PIN code? */ - if (c->spd.this.sc && !c->spd.this.sc->valid && whackfd != NULL_FD) - { - scx_get_pin(c->spd.this.sc, whackfd); - } - if (c->spd.this.sc && !c->spd.this.sc->valid) - { - loglog(RC_NOVALIDPIN, "cannot initiate connection without valid PIN"); - } - else - { - - if (c->spd.that.allow_any) - { - c = instantiate(c, &c->spd.that.host_addr, - c->spd.that.host_port, c->spd.that.id); - } - - /* We will only request an IPsec SA if policy isn't empty - * (ignoring Main Mode items). - * This is a fudge, but not yet important. - * If we are to proceed asynchronously, whackfd will be NULL_FD. - */ - c->policy |= POLICY_UP; - ipsecdoi_initiate(whackfd, c, c->policy, 1, SOS_NOBODY); - whackfd = NULL_FD; /* protect from close */ - } - } - reset_cur_connection(); - } - close_any(whackfd); -} - -/* (Possibly) Opportunistic Initiation: - * Knowing clients (single IP addresses), try to build an tunnel. - * This may involve discovering a gateway and instantiating an - * Opportunistic connection. Called when a packet is caught by - * a %trap, or when whack --oppohere --oppothere is used. - * It may turn out that an existing or non-opporunistic connnection - * can handle the traffic. - * - * Most of the code will be restarted if an ADNS request is made - * to discover the gateway. The only difference between the first - * and second entry is whether gateways_from_dns is NULL or not. - * initiate_opportunistic: initial entrypoint - * continue_oppo: where we pickup when ADNS result arrives - * initiate_opportunistic_body: main body shared by above routines - * cannot_oppo: a helper function to log a diagnostic - * This structure repeats a lot of code when the ADNS result arrives. - * This seems like a waste, but anything learned the first time through - * may no longer be true! - * - * After the first IKE message is sent, the regular state machinery - * carries negotiation forward. - */ - -enum find_oppo_step { - fos_start, - fos_myid_ip_txt, - fos_myid_hostname_txt, - fos_myid_ip_key, - fos_myid_hostname_key, - fos_our_client, - fos_our_txt, -#ifdef USE_KEYRR - fos_our_key, -#endif /* USE_KEYRR */ - fos_his_client, - fos_done -}; - -#ifdef DEBUG -static const char *const oppo_step_name[] = { - "fos_start", - "fos_myid_ip_txt", - "fos_myid_hostname_txt", - "fos_myid_ip_key", - "fos_myid_hostname_key", - "fos_our_client", - "fos_our_txt", -#ifdef USE_KEYRR - "fos_our_key", -#endif /* USE_KEYRR */ - "fos_his_client", - "fos_done" -}; -#endif /* DEBUG */ - -struct find_oppo_bundle { - enum find_oppo_step step; - err_t want; - bool failure_ok; /* if true, continue_oppo should not die on DNS failure */ - ip_address our_client; /* not pointer! */ - ip_address peer_client; - int transport_proto; - bool held; - policy_prio_t policy_prio; - ipsec_spi_t failure_shunt; /* in host order! 0 for delete. */ - int whackfd; -}; - -struct find_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct find_oppo_bundle b; -}; - -static void cannot_oppo(connection_t *c, struct find_oppo_bundle *b, err_t ugh) -{ - char pcb[ADDRTOT_BUF]; - char ocb[ADDRTOT_BUF]; - - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - - DBG(DBG_DNS | DBG_OPPO, DBG_log("Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh)); - - whack_log(RC_OPPOFAILURE - , "Can't Opportunistically initiate for %s to %s: %s" - , ocb, pcb, ugh); - - if (c && c->policy_next) - { - /* there is some policy that comes afterwards */ - struct spd_route *shunt_spd; - connection_t *nc = c->policy_next; - struct state *st; - - passert(c->kind == CK_TEMPLATE); - passert(c->policy_next->kind == CK_PERMANENT); - - DBG(DBG_OPPO, DBG_log("OE failed for %s to %s, but %s overrides shunt" - , ocb, pcb, c->policy_next->name)); - - /* - * okay, here we need add to the "next" policy, which is ought - * to be an instance. - * We will add another entry to the spd_route list for the specific - * situation that we have. - */ - - shunt_spd = clone_thing(nc->spd); - - shunt_spd->next = nc->spd.next; - nc->spd.next = shunt_spd; - - happy(addrtosubnet(&b->peer_client, &shunt_spd->that.client)); - - if (sameaddr(&b->peer_client, &shunt_spd->that.host_addr)) - shunt_spd->that.has_client = FALSE; - - /* - * override the tunnel destination with the one from the secondaried - * policy - */ - shunt_spd->that.host_addr = nc->spd.that.host_addr; - - /* now, lookup the state, and poke it up. - */ - - st = state_with_serialno(nc->newest_ipsec_sa); - - /* XXX what to do if the IPSEC SA has died? */ - passert(st != NULL); - - /* link the new connection instance to the state's list of - * connections - */ - - DBG(DBG_OPPO, DBG_log("installing state: %ld for %s to %s" - , nc->newest_ipsec_sa - , ocb, pcb)); - -#ifdef DEBUG - if (DBGP(DBG_OPPO | DBG_CONTROLMORE)) - { - char state_buf[LOG_WIDTH]; - char state_buf2[LOG_WIDTH]; - time_t n = now(); - - fmt_state(FALSE, st, n - , state_buf, sizeof(state_buf) - , state_buf2, sizeof(state_buf2)); - DBG_log("cannot_oppo, failure SA1: %s", state_buf); - DBG_log("cannot_oppo, failure SA2: %s", state_buf2); - } -#endif /* DEBUG */ - - if (!route_and_eroute(c, shunt_spd, st)) - { - whack_log(RC_OPPOFAILURE - , "failed to instantiate shunt policy %s for %s to %s" - , c->name - , ocb, pcb); - } - return; - } -} - -static void initiate_opportunistic_body(struct find_oppo_bundle *b - , struct adns_continuation *ac, err_t ac_ugh); /* forward */ - -void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, int transport_proto, - bool held, int whackfd) -{ - struct find_oppo_bundle b; - - b.want = (whackfd == NULL_FD ? "whack" : "acquire"); - b.failure_ok = FALSE; - b.our_client = *our_client; - b.peer_client = *peer_client; - b.transport_proto = transport_proto; - b.held = held; - b.policy_prio = BOTTOM_PRIO; - b.failure_shunt = 0; - b.whackfd = whackfd; - b.step = fos_start; - initiate_opportunistic_body(&b, NULL, NULL); -} - -#ifdef ADNS - -static void continue_oppo(struct adns_continuation *acr, err_t ugh) -{ - struct find_oppo_continuation *cr = (void *)acr; /* inherit, damn you! */ - connection_t *c; - bool was_held = cr->b.held; - int whackfd = cr->b.whackfd; - - /* note: cr->id has no resources; cr->sgw_id is ID_ANY: - * neither need freeing. - */ - whack_log_fd = whackfd; - -#ifdef DEBUG - /* if we're going to ignore the error, at least note it in debugging log */ - if (cr->b.failure_ok && ugh) - { - DBG(DBG_CONTROL | DBG_DNS, - { - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - DBG_log("continuing from failed DNS lookup for %s, %s to %s: %s" - , cr->b.want, ocb, pcb, ugh); - }); - } -#endif - - if (!cr->b.failure_ok && ugh) - { - c = find_connection_for_clients(NULL, &cr->b.our_client, &cr->b.peer_client - , cr->b.transport_proto); - cannot_oppo(c, &cr->b - , builddiag("%s: %s", cr->b.want, ugh)); - } - else if (was_held && !cr->b.held) - { - /* was_held indicates we were started due to a %trap firing - * (as opposed to a "whack --oppohere --oppothere"). - * Since the %hold has gone, we can assume that somebody else - * has beaten us to the punch. We can go home. But lets log it. - */ - char ocb[ADDRTOT_BUF]; - char pcb[ADDRTOT_BUF]; - - addrtot(&cr->b.our_client, 0, ocb, sizeof(ocb)); - addrtot(&cr->b.peer_client, 0, pcb, sizeof(pcb)); - - loglog(RC_COMMENT - , "%%hold otherwise handled during DNS lookup for Opportunistic Initiation for %s to %s" - , ocb, pcb); - } - else - { - initiate_opportunistic_body(&cr->b, &cr->ac, ugh); - whackfd = NULL_FD; /* was handed off */ - } - - whack_log_fd = NULL_FD; - close_any(whackfd); -} - -#endif /* ADNS */ - -#ifdef USE_KEYRR -static err_t check_key_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, &kr->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} -#endif /* USE_KEYRR */ - -#ifdef ADNS - -static err_t check_txt_recs(enum myid_state try_state, const connection_t *c, - struct adns_continuation *ac) -{ - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - enum myid_state old_myid_state = myid_state; - private_key_t *private; - err_t ugh = NULL; - - myid_state = try_state; - - if (old_myid_state != myid_state - && old_myid_state == MYID_SPECIFIED) - { - ugh = "%myid was specified while we were guessing"; - } - else if ((private = get_private_key(c)) == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR found for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - public_key_t *pub_key = gwp->key->public_key; - - ugh = "all our TXT RRs have the wrong public key"; - if (pub_key->get_type(pub_key) == KEY_RSA && - private->belongs_to(private, pub_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - if (ugh) - { - myid_state = old_myid_state; - } - return ugh; -} - -#endif /* ADNS */ - - -/* note: gateways_from_dns must be NULL iff this is the first call */ -static void initiate_opportunistic_body(struct find_oppo_bundle *b, - struct adns_continuation *ac, - err_t ac_ugh) -{ - connection_t *c; - struct spd_route *sr; - - /* What connection shall we use? - * First try for one that explicitly handles the clients. - */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - int ourport; - int hisport; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - ourport = ntohs(portof(&b->our_client)); - hisport = ntohs(portof(&b->peer_client)); - DBG_log("initiate on demand from %s:%d to %s:%d proto=%d state: %s because: %s" - , ours, ourport, his, hisport, b->transport_proto - , oppo_step_name[b->step], b->want); - }); - if (isanyaddr(&b->our_client) || isanyaddr(&b->peer_client)) - { - cannot_oppo(NULL, b, "impossible IP address"); - } - else if ((c = find_connection_for_clients(&sr - , &b->our_client - , &b->peer_client - , b->transport_proto)) == NULL) - { - /* No connection explicitly handles the clients and there - * are no Opportunistic connections -- whine and give up. - * The failure policy cannot be gotten from a connection; we pick %pass. - */ - cannot_oppo(NULL, b, "no routed Opportunistic template covers this pair"); - } - else if (c->kind != CK_TEMPLATE) - { - /* We've found a connection that can serve. - * Do we have to initiate it? - * Not if there is currently an IPSEC SA. - * But if there is an IPSEC SA, then the kernel would not - * have generated the acquire. So we assume that there isn't one. - * This may be redundant if a non-opportunistic - * negotiation is already being attempted. - */ - - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - - if(c->kind == CK_INSTANCE) - { - char cib[CONN_INST_BUF]; - /* there is already an instance being negotiated, no nothing */ - DBG(DBG_CONTROL, DBG_log("found existing instance \"%s\"%s, rekeying it" - , c->name - , (fmt_conn_instance(c, cib), cib))); - /* XXX-mcr - return; */ - } - - /* otherwise, there is some kind of static conn that can handle - * this connection, so we initiate it */ - - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, sr, b->transport_proto, &b->our_client, &b->peer_client); - } - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } -#ifdef ADNS - else - { - /* We are handling an opportunistic situation. - * This involves several DNS lookup steps that require suspension. - * Note: many facts might change while we're suspended. - * Here be dragons. - * - * The first chunk of code handles the result of the previous - * DNS query (if any). It also selects the kind of the next step. - * The second chunk initiates the next DNS query (if any). - */ - enum find_oppo_step next_step = fos_myid_ip_txt; - err_t ugh = ac_ugh; - char mycredentialstr[BUF_LEN]; - char cib[CONN_INST_BUF]; - - DBG(DBG_CONTROL, DBG_log("creating new instance from \"%s\"%s", - c->name, (fmt_conn_instance(c, cib), cib))); - snprintf(mycredentialstr, BUF_LEN, "%Y", sr->this.id); - - /* handle any DNS answer; select next step */ - switch (b->step) - { - case fos_start: - /* just starting out: select first query step */ - next_step = fos_myid_ip_txt; - break; - - case fos_myid_ip_txt: /* TXT for our default IP address as %myid */ - ugh = check_txt_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:TXT) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_myid_hostname_txt; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:TXT) as identity!", - myids[MYID_IP]); - logged_myid_ip_txt_warning = TRUE; - } - - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_txt: /* TXT for our hostname as %myid */ - ugh = check_txt_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our hostname as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:TXT) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_txt_warning = TRUE; - } -#ifdef USE_KEYRR - next_step = fos_myid_ip_key; - ugh = NULL; /* failure can be recovered from */ -#endif - } - else - { - /* we can use our hostname as OE identity for initiation */ - if (!logged_myid_fqdn_txt_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:TXT) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_txt_warning = TRUE; - } - next_step = fos_our_client; - } - break; - -#ifdef USE_KEYRR - case fos_myid_ip_key: /* KEY for our default IP address as %myid */ - ugh = check_key_recs(MYID_IP, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh)); - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our IP (%Y:KEY) as identity: %s", - myids[MYID_IP], ugh); - logged_myid_ip_key_warning = TRUE; - } - - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_ip_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our IP (%Y:KEY) as identity!", - myids[MYID_IP]); - logged_myid_ip_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; - - case fos_myid_hostname_key: /* KEY for our hostname as %myid */ - ugh = check_key_recs(MYID_HOSTNAME, c, ac); - if (ugh) - { - /* cannot use our IP as OE identitiy for initiation */ - DBG(DBG_OPPO, - DBG_log("can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh)); - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "can not use our hostname (%Y:KEY) as identity: %s", - myids[MYID_HOSTNAME], ugh); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_myid_hostname_key; - ugh = NULL; /* failure can be recovered from */ - } - else - { - /* we can use our IP as OE identity for initiation */ - if (!logged_myid_fqdn_key_warning) - { - loglog(RC_LOG_SERIOUS, - "using our hostname (%Y:KEY) as identity!", - myids[MYID_HOSTNAME]); - logged_myid_fqdn_key_warning = TRUE; - } - next_step = fos_our_client; - } - break; -#endif - - case fos_our_client: /* TXT for our client */ - { - /* Our client is not us: we must check the TXT records. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* normal situation */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (sameaddr(&sr->this.host_addr, &b->our_client)) - { - /* this wasn't true when we started -- bail */ - ugh = "our IP address changed underfoot"; - } - else if (!ac->sgw_id->equals(ac->sgw_id, sr->this.id)) - { - /* this wasn't true when we started -- bail */ - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in quick_inI1_outR1_tail - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for our client delegates us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for our client has wrong key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we have a tentative win: - * we need to check our KEY record to be sure. - */ - if (!gwp->gw_key_present) - { - /* Success, but the TXT had no key - * so we must check our our own KEY records. - */ - next_step = fos_our_txt; - ugh = NULL; /* good! */ - break; - } - if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - } - break; - - case fos_our_txt: /* TXT for us */ - { - /* Check if TXT lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* unless we decide to look for KEY RR */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!ac->id->equals(ac->id, c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - struct gw_info *gwp; - - ugh = "no TXT RR for us"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "TXT RR for us has wrong key"; - if (gwp->gw_key_present && - private->belongs_to(private, gwp->key->public_key)) - { - DBG(DBG_CONTROL, - DBG_log("initiate on demand found TXT with right public key at: %s" - , mycredentialstr)); - ugh = NULL; - break; - } - } -#ifdef USE_KEYRR - if (ugh) - { - /* if no TXT with right key, try KEY */ - DBG(DBG_CONTROL, - DBG_log("will try for KEY RR since initiate on demand found %s: %s" - , ugh, mycredentialstr)); - next_step = fos_our_key; - ugh = NULL; - } -#endif - } - } - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - { - /* Check if KEY lookup yielded good results. - * Looking up based on our ID. Used if - * client is ourself, or if TXT had no public key. - * Note: if c is different this time, there is - * a chance that we did the wrong query. - * If so, treat as a kind of failure. - */ - private_key_t *private = get_private_key(c); - - next_step = fos_his_client; /* always */ - - if (private == NULL) - { - ugh = "we don't know our own RSA key"; - } - else if (!same_id(&ac->id, &c->spd.this.id)) - { - ugh = "our ID changed underfoot"; - } - else - { - /* Similar to code in RSA_check_signature - * for checking the other side. - */ - pubkey_list_t *kr; - - ugh = "no KEY RR found for us (and no good TXT RR)"; - for (kr = ac->keys_from_dns; kr != NULL; kr = kr->next) - { - ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)"; - if (kr->key->alg == PUBKEY_ALG_RSA - && private->belongs_to(private, kr->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS - , "found KEY RR but not TXT RR for %s. See http://www.freeswan.org/err/txt-change.html." - , mycredentialstr); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - { - /* We've finished last DNS queries: TXT for his client. - * Using the information, try to instantiate a connection - * and start negotiating. - * We now know the peer. The chosing of "c" ignored this, - * so we will disregard its current value. - * !!! We need to randomize the entry in gw that we choose. - */ - next_step = fos_done; /* no more queries */ - - c = build_outgoing_opportunistic_connection(ac->gateways_from_dns - , &b->our_client - , &b->peer_client); - - if (c == NULL) - { - /* We cannot seem to instantiate a suitable connection: - * complain clearly. - */ - char ocb[ADDRTOT_BUF], pcb[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ocb, sizeof(ocb)); - addrtot(&b->peer_client, 0, pcb, sizeof(pcb)); - loglog(RC_OPPOFAILURE, - "no suitable connection for opportunism " - "between %s and %s with %Y as peer", - ocb, pcb, ac->gateways_from_dns->gw_id); - } - else - { - /* If we are to proceed asynchronously, b->whackfd will be NULL_FD. */ - passert(c->kind == CK_INSTANCE); - passert(c->gw_info != NULL); - passert(HAS_IPSEC_POLICY(c->policy)); - passert(LHAS(LELEM(RT_UNROUTED) | LELEM(RT_ROUTED_PROSPECTIVE), c->spd.routing)); - if (b->held) - { - /* what should we do on failure? */ - (void) assign_hold(c, &c->spd - , b->transport_proto - , &b->our_client, &b->peer_client); - } - c->gw_info->key->last_tried_time = now(); - ipsecdoi_initiate(b->whackfd, c, c->policy, 1, SOS_NOBODY); - b->whackfd = NULL_FD; /* protect from close */ - } - } - break; - - default: - bad_case(b->step); - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[ADDRTOT_BUF]; - char his[ADDRTOT_BUF]; - - addrtot(&b->our_client, 0, ours, sizeof(ours)); - addrtot(&b->peer_client, 0, his, sizeof(his)); - DBG_log("initiate on demand from %s to %s new state: %s with ugh: %s" - , ours, his, oppo_step_name[b->step], ugh ? ugh : "ok"); - }); - - if (ugh) - { - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cannot_oppo(c, b, ugh); - } - else if (next_step == fos_done) - { - /* nothing to do */ - } - else - { - /* set up the next query */ - struct find_oppo_continuation *cr = malloc_thing(struct find_oppo_continuation); - identification_t *id; - - b->policy_prio = c->prio; - b->failure_shunt = shunt_policy_spi(c, FALSE); - cr->b = *b; /* copy; start hand off of whackfd */ - cr->b.failure_ok = FALSE; - cr->b.step = next_step; - - for (sr = &c->spd - ; sr!=NULL && !sameaddr(&sr->this.host_addr, &b->our_client) - ; sr = sr->next) - ; - - if (sr == NULL) - sr = &c->spd; - - /* If a %hold shunt has replaced the eroute for this template, - * record this fact. - */ - if (b->held - && sr->routing == RT_ROUTED_PROSPECTIVE && eclipsable(sr)) - { - sr->routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - - /* Switch to issue next query. - * A case may turn out to be unnecessary. If so, it falls - * through to the next case. - * Figuring out what %myid can stand for must be done before - * our client credentials are looked up: we must know what - * the client credentials may use to identify us. - * On the other hand, our own credentials should be looked - * up after our clients in case our credentials are not - * needed at all. - * XXX this is a wasted effort if we don't have credentials - * BUT they are not needed. - */ - switch (next_step) - { - case fos_myid_ip_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "TXT record for IP address as %myid"; - ugh = start_adns_query(myids[MYID_IP], myids[MYID_IP], - T_TXT, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_txt; - /* fall through */ - - case fos_myid_hostname_txt: - if (c->spd.this.id->get_type(c->spd.this.id) == ID_MYID - && myid_state != MYID_SPECIFIED) - { -#ifdef USE_KEYRR - cr->b.failure_ok = TRUE; -#else - cr->b.failure_ok = FALSE; -#endif - cr->b.want = b->want = "TXT record for hostname as %myid"; - ugh = start_adns_query(myids[MYID_HOSTNAME], - myids[MYID_HOSTNAME], - T_TXT, continue_oppo, &cr->ac); - break; - } - -#ifdef USE_KEYRR - cr->b.step = fos_myid_ip_key; - /* fall through */ - - case fos_myid_ip_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = TRUE; - cr->b.want = b->want = "KEY record for IP address as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_IP], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } - cr->b.step = fos_myid_hostname_key; - /* fall through */ - - case fos_myid_hostname_key: - if (c->spd.this.id.kind == ID_MYID - && myid_state != MYID_SPECIFIED) - { - cr->b.failure_ok = FALSE; /* last attempt! */ - cr->b.want = b->want = "KEY record for hostname as %myid (no good TXT)"; - ugh = start_adns_query(myids[MYID_HOSTNAME], NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; - } -#endif - cr->b.step = fos_our_client; - /* fall through */ - - case fos_our_client: /* TXT for our client */ - if (!sameaddr(&c->spd.this.host_addr, &b->our_client)) - { - /* Check that at least one TXT(reverse(b->our_client)) is workable. - * Note: {unshare|free}_id_content not needed for id: ephemeral. - */ - cr->b.want = b->want = "our client's TXT record"; - id = identification_create_from_sockaddr((sockaddr_t*)&b->our_client); - ugh = start_adns_query(id, c->spd.this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - } - cr->b.step = fos_our_txt; - /* fall through */ - - case fos_our_txt: /* TXT for us */ - cr->b.failure_ok = b->failure_ok = TRUE; - cr->b.want = b->want = "our TXT record"; - ugh = start_adns_query(sr->this.id, sr->this.id, /* we are the security gateway */ - T_TXT, continue_oppo, &cr->ac); - break; - -#ifdef USE_KEYRR - case fos_our_key: /* KEY for us */ - cr->b.want = b->want = "our KEY record"; - cr->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(sr->this.id, NULL, /* security gateway meaningless */ - T_KEY, continue_oppo, &cr->ac); - break; -#endif /* USE_KEYRR */ - - case fos_his_client: /* TXT for his client */ - /* note: {unshare|free}_id_content not needed for id: ephemeral */ - cr->b.want = b->want = "target's TXT record"; - cr->b.failure_ok = b->failure_ok = FALSE; - id = identification_create_from_sockaddr((sockaddr_t*)&b->peer_client); - ugh = start_adns_query(id, NULL, /* security gateway unconstrained */ - T_TXT, continue_oppo, &cr->ac); - id->destroy(id); - break; - - default: - bad_case(next_step); - } - - if (ugh == NULL) - b->whackfd = NULL_FD; /* complete hand-off */ - else - cannot_oppo(c, b, ugh); - } - } -#endif /* ADNS */ - close_any(b->whackfd); -} - -void terminate_connection(const char *nm) -{ - /* Loop because more than one may match (master and instances) - * But at least one is required (enforced by con_by_name). - */ - connection_t *c = con_by_name(nm, TRUE); - - if (c == NULL || !c->ikev1) - return; - - do - { - connection_t *n = c->ac_next; /* grab this before c might disappear */ - - if (streq(c->name, nm) - && c->kind >= CK_PERMANENT - && !NEVER_NEGOTIATE(c->policy)) - { - set_cur_connection(c); - plog("terminating SAs using this connection"); - c->policy &= ~POLICY_UP; - flush_pending_by_connection(c); - delete_states_by_connection(c, FALSE); - if (c->kind == CK_INSTANCE) - delete_connection(c, FALSE); - reset_cur_connection(); - } - c = n; - } while (c); -} - -/* an ISAKMP SA has been established. - * Note the serial number, and release any connections with - * the same peer ID but different peer IP address. - */ -bool uniqueIDs = FALSE; /* --uniqueids? */ - -void ISAKMP_SA_established(connection_t *c, so_serial_t serial) -{ - c->newest_isakmp_sa = serial; - - /* the connection is now oriented so that we are able to determine - * whether we are a mode config server with a virtual IP to send. - */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip) && - !c->spd.that.has_natip) - { - c->spd.that.modecfg = TRUE; - } - - if (uniqueIDs) - { - /* for all connections: if the same Phase 1 IDs are used - * for a different IP address, unorient that connection. - */ - connection_t *d; - - for (d = connections; d != NULL; ) - { - connection_t *next = d->ac_next; /* might move underneath us */ - - if (d->kind >= CK_PERMANENT && - c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - c->spd.that.id->equals(c->spd.that.id, d->spd.that.id) && - !sameaddr(&c->spd.that.host_addr, &d->spd.that.host_addr)) - { - release_connection(d, FALSE); - } - d = next; - } - } -} - -/* Find the connection to connection c's peer's client with the - * largest value of .routing. All other things being equal, - * preference is given to c. If none is routed, return NULL. - * - * If erop is non-null, set *erop to a connection sharing both - * our client subnet and peer's client subnet with the largest value - * of .routing. If none is erouted, set *erop to NULL. - * - * The return value is used to find other connections sharing a route. - * *erop is used to find other connections sharing an eroute. - */ -connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp) -{ - connection_t *d - , *best_ro = c - , *best_ero = c; - struct spd_route *srd, *src; - struct spd_route *best_sr, *best_esr; - enum routing_t best_routing, best_erouting; - - passert(oriented(*c)); - best_sr = NULL; - best_esr = NULL; - best_routing = c->spd.routing; - best_erouting = best_routing; - - for (d = connections; d != NULL; d = d->ac_next) - { - for (srd = &d->spd; srd; srd = srd->next) - { - if (srd->routing == RT_UNROUTED) - continue; - - for (src = &c->spd; src; src=src->next) - { - if (!samesubnet(&src->that.client, &srd->that.client)) - { - continue; - } - if (src->that.protocol != srd->that.protocol) - { - continue; - } - if (src->that.port != srd->that.port) - { - continue; - } - if (src->mark_out.value != srd->mark_out.value) - { - continue; - } - passert(oriented(*d)); - if (srd->routing > best_routing) - { - best_ro = d; - best_sr = srd; - best_routing = srd->routing; - } - - if (!samesubnet(&src->this.client, &srd->this.client)) - { - continue; - } - if (src->this.protocol != srd->this.protocol) - { - continue; - } - if (src->this.port != srd->this.port) - { - continue; - } - if (src->mark_in.value != srd->mark_in.value) - { - continue; - } - if (srd->routing > best_erouting) - { - best_ero = d; - best_esr = srd; - best_erouting = srd->routing; - } - } - } - } - - DBG(DBG_CONTROL, - { - char cib[CONN_INST_BUF]; - err_t m = builddiag("route owner of \"%s\"%s %s:" - , c->name - , (fmt_conn_instance(c, cib), cib) - , enum_name(&routing_story, c->spd.routing)); - - if (!routed(best_ro->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ro == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ro->name - , (fmt_conn_instance(best_ro, cib), cib) - , enum_name(&routing_story, best_ro->spd.routing)); - - if (erop) - { - m = builddiag("%s; eroute owner:", m); - if (!erouted(best_ero->spd.routing)) - m = builddiag("%s NULL", m); - else if (best_ero == c) - m = builddiag("%s self", m); - else - m = builddiag("%s \"%s\"%s %s", m - , best_ero->name - , (fmt_conn_instance(best_ero, cib), cib) - , enum_name(&routing_story, best_ero->spd.routing)); - } - - DBG_log("%s", m); - }); - - if (erop) - { - *erop = erouted(best_erouting)? best_ero : NULL; - } - if (srp) - { - *srp = best_sr; - if (esrp) - { - *esrp = best_esr; - } - } - - return routed(best_routing)? best_ro : NULL; -} - -/* Find a connection that owns the shunt eroute between subnets. - * There ought to be only one. - * This might get to be a bottleneck -- try hashing if it does. - */ -connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his) -{ - connection_t *c; - struct spd_route *sr; - - for (c = connections; c != NULL; c = c->ac_next) - { - for (sr = &c->spd; sr; sr = sr->next) - { - if (shunt_erouted(sr->routing) - && samesubnet(ours, &sr->this.client) - && samesubnet(his, &sr->that.client)) - return c; - } - } - return NULL; -} - -/* Find some connection with this pair of hosts. - * We don't know enough to chose amongst those available. - * ??? no longer usefully different from find_host_pair_connections - */ -connection_t *find_host_connection(const ip_address *me, u_int16_t my_port, - const ip_address *him, u_int16_t his_port, - lset_t policy) -{ - connection_t *c = find_host_pair_connections(me, my_port, him, his_port); - - if (policy != LEMPTY) - { - lset_t auth_requested = policy & POLICY_ID_AUTH_MASK; - - /* if we have requirements for the policy, - * choose the first matching connection. - */ - while (c) - { - if (c->policy & auth_requested) - { - break; - } - c = c->hp_next; - } - } - return c; -} - -/* given an up-until-now satisfactory connection, find the best connection - * now that we just got the Phase 1 Id Payload from the peer. - * - * Comments in the code describe the (tricky!) matching criteria. - * Although this routine could handle the initiator case, - * it isn't currently called in this case. - * If it were, it could "upgrade" an Opportunistic Connection - * to a Road Warrior Connection if a suitable Peer ID were found. - * - * In RFC 2409 "The Internet Key Exchange (IKE)", - * in 5.1 "IKE Phase 1 Authenticated With Signatures", describing Main - * Mode: - * - * Initiator Responder - * ----------- ----------- - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, [ CERT, ] SIG_I --> - * <-- HDR*, IDir, [ CERT, ] SIG_R - * - * In 5.4 "Phase 1 Authenticated With a Pre-Shared Key": - * - * HDR, SA --> - * <-- HDR, SA - * HDR, KE, Ni --> - * <-- HDR, KE, Nr - * HDR*, IDii, HASH_I --> - * <-- HDR*, IDir, HASH_R - * - * refine_host_connection could be called in two case: - * - * - the Responder receives the IDii payload: - * + [PSK] after using PSK to decode this message - * + before sending its IDir payload - * + before using its ID in HASH_R computation - * + [DSig] before using its private key to sign SIG_R - * + before using the Initiator's ID in HASH_I calculation - * + [DSig] before using the Initiator's public key to check SIG_I - * - * - the Initiator receives the IDir payload: - * + [PSK] after using PSK to encode previous message and decode this message - * + after sending its IDii payload - * + after using its ID in HASH_I computation - * + [DSig] after using its private key to sign SIG_I - * + before using the Responder's ID to compute HASH_R - * + [DSig] before using Responder's public key to check SIG_R - * - * refine_host_connection can choose a different connection, as long as - * nothing already used is changed. - * - * In the Initiator case, the particular connection might have been - * specified by whatever provoked Pluto to initiate. For example: - * whack --initiate connection-name - * The advantages of switching connections when we're the Initiator seem - * less important than the disadvantages, so after FreeS/WAN 1.9, we - * don't do this. - */ -#define PRIO_NO_MATCH_FOUND 2048 - -connection_t *refine_host_connection(const struct state *st, - identification_t *peer_id, - identification_t *peer_ca) -{ - connection_t *c = st->st_connection; - connection_t *d; - connection_t *best_found = NULL; - u_int16_t auth = st->st_oakley.auth; - lset_t auth_policy = POLICY_PSK; - const chunk_t *psk = NULL; - bool wcpip; /* wildcard Peer IP? */ - int best_prio = PRIO_NO_MATCH_FOUND; - int our_pathlen, peer_pathlen; - - if (c->spd.that.id->equals(c->spd.that.id, peer_id) && - trusted_ca(peer_ca, c->spd.that.ca, &peer_pathlen) && - peer_pathlen == 0 && - match_requested_ca(c->requested_ca, c->spd.this.ca, &our_pathlen) && - our_pathlen == 0) - { - DBG(DBG_CONTROL, - DBG_log("current connection is a full match" - " -- no need to look further"); - ) - return c; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - auth_policy = POLICY_PSK; - psk = get_preshared_secret(c); - /* It should be virtually impossible to fail to find PSK: - * we just used it to decode the current message! - */ - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth_policy = POLICY_XAUTH_PSK; - psk = get_preshared_secret(c); - if (psk == NULL) - { - return NULL; /* cannot determine PSK! */ - } - break; - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - auth_policy = POLICY_PUBKEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth_policy = POLICY_XAUTH_RSASIG; - break; - default: - bad_case(auth); - } - - /* The current connection won't do: search for one that will. - * First search for one with the same pair of hosts. - * If that fails, search for a suitable Road Warrior or Opportunistic - * connection (i.e. wildcard peer IP). - * We need to match: - * - peer_id (slightly complicated by instantiation) - * - if PSK auth, the key must not change (we used it to decode message) - * - policy-as-used must be acceptable to new connection - */ - d = c->host_pair->connections; - for (wcpip = FALSE; ; wcpip = TRUE) - { - for (; d != NULL; d = d->hp_next) - { - const char *match_name[] = {"no", "ok"}; - - id_match_t match_level = peer_id->matches(peer_id, d->spd.that.id); - - bool matching_id = match_level > ID_MATCH_NONE; - - bool matching_auth = (d->policy & auth_policy) != LEMPTY; - - bool matching_trust = trusted_ca(peer_ca - , d->spd.that.ca, &peer_pathlen); - bool matching_request = match_requested_ca(c->requested_ca - , d->spd.this.ca, &our_pathlen); - bool match = matching_id && matching_auth && matching_trust; - - int prio = (ID_MATCH_PERFECT) * !matching_request + - ID_MATCH_PERFECT - match_level; - - prio = (X509_MAX_PATH_LEN + 1) * prio + peer_pathlen; - prio = (X509_MAX_PATH_LEN + 1) * prio + our_pathlen; - - DBG(DBG_CONTROLMORE, - DBG_log("%s: %s match (id: %s, auth: %s, trust: %s, request: %s, prio: %4d)" - , d->name - , match ? "full":" no" - , match_name[matching_id] - , match_name[matching_auth] - , match_name[matching_trust] - , match_name[matching_request] - , match ? prio:PRIO_NO_MATCH_FOUND) - ) - - /* do we have a match? */ - if (!match) - { - continue; - } - - /* ignore group connections */ - if (d->policy & POLICY_GROUP) - { - continue; - } - - if (c->spd.that.host_port != d->spd.that.host_port - && d->kind == CK_INSTANCE) - { - continue; - } - - switch (auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - /* secret must match the one we already used */ - { - const chunk_t *dpsk = get_preshared_secret(d); - - if (dpsk == NULL) - { - continue; /* no secret */ - } - if (psk != dpsk) - { - if (psk->len != dpsk->len - || memcmp(psk->ptr, dpsk->ptr, psk->len) != 0) - { - continue; /* different secret */ - } - } - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - /* - * We must at least be able to find our private key - .*/ - if (d->spd.this.sc == NULL /* no smartcard */ - && get_private_key(d) == NULL) /* no private key */ - { - continue; - } - break; - - default: - bad_case(auth); - } - - /* d has passed all the tests. - * We'll go with it if the Peer ID was an exact match. - */ - if (prio == 0) - { - return d; - } - - /* We'll remember it as best_found in case an exact - * match doesn't come along. - */ - if (prio < best_prio) - { - best_found = d; - best_prio = prio; - } - } - if (wcpip) - return best_found; /* been around twice already */ - - /* Starting second time around. - * We're willing to settle for a connection that needs Peer IP - * instantiated: Road Warrior or Opportunistic. - * Look on list of connections for host pair with wildcard Peer IP - */ - d = find_host_pair_connections(&c->spd.this.host_addr, c->spd.this.host_port - , (ip_address *)NULL, c->spd.that.host_port); - } -} - -/** - * With virtual addressing, we must not allow someone to use an already - * used (by another id) addr/net. - */ -static bool is_virtual_net_used(const ip_subnet *peer_net, - identification_t *peer_id) -{ - connection_t *d; - - for (d = connections; d != NULL; d = d->ac_next) - { - switch (d->kind) - { - case CK_PERMANENT: - case CK_INSTANCE: - if ((subnetinsubnet(peer_net,&d->spd.that.client) || - subnetinsubnet(&d->spd.that.client,peer_net)) - && !d->spd.that.id->equals(d->spd.that.id, peer_id)) - { - char client[SUBNETTOT_BUF]; - - subnettot(peer_net, 0, client, sizeof(client)); - plog("Virtual IP %s is already used by '%Y'", - client, d->spd.that.id); - plog("Your ID is '%Y'", peer_id); - - return TRUE; /* already used by another one */ - } - break; - case CK_GOING_AWAY: - default: - break; - } - } - return FALSE; /* you can safely use it */ -} - -/* find_client_connection: given a connection suitable for ISAKMP - * (i.e. the hosts match), find a one suitable for IPSEC - * (i.e. with matching clients). - * - * If we don't find an exact match (not even our current connection), - * we try for one that still needs instantiation. Try Road Warrior - * abstract connections and the Opportunistic abstract connections. - * This requires inverse instantiation: abstraction. - * - * After failing to find an exact match, we abstract the peer - * to be NO_IP (the wildcard value). This enables matches with - * Road Warrior and Opportunistic abstract connections. - * - * After failing that search, we also abstract the Phase 1 peer ID - * if possible. If the peer's ID was the peer's IP address, we make - * it NO_ID; instantiation will make it the peer's IP address again. - * - * If searching for a Road Warrior abstract connection fails, - * and conditions are suitable, we search for the best Opportunistic - * abstract connection. - * - * Note: in the end, both Phase 1 IDs must be preserved, after any - * instantiation. They are the IDs that have been authenticated. - */ - -#define PATH_WEIGHT 1 -#define WILD_WEIGHT (X509_MAX_PATH_LEN+1) -#define PRIO_WEIGHT (ID_MATCH_PERFECT+1) * WILD_WEIGHT - -/* fc_try: a helper function for find_client_connection */ -static connection_t *fc_try(const connection_t *c, struct host_pair *hp, - identification_t *peer_id, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - - const bool peer_net_is_host = subnetisaddr(peer_net, &c->spd.that.host_addr); - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - - if (d->policy & POLICY_GROUP) - { - continue; - } - - match_level = c->spd.that.id->matches(c->spd.that.id, d->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* non-Opportunistic case: - * our_client must match. - * - * So must peer_client, but the testing is complicated - * by the fact that the peer might be a wildcard - * and if so, the default value of that.client - * won't match the default peer_net. The appropriate test: - * - * If d has a peer client, it must match peer_net. - * If d has no peer client, peer_net must just have peer itself. - */ - - for (sr = &d->spd; best != d && sr != NULL; sr = sr->next) - { - policy_prio_t prio; -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try trying " - "%s:%s:%d/%d -> %s:%d/%d vs %s:%s:%d/%d -> %s:%d/%d" - , c->name, s1, c->spd.this.protocol, c->spd.this.port - , d1, c->spd.that.protocol, c->spd.that.port - , d->name, s3, sr->this.protocol, sr->this.port - , d3, sr->that.protocol, sr->that.port); - } -#endif /* DEBUG */ - - if (!samesubnet(&sr->this.client, our_net)) - { - continue; - } - if (sr->that.has_client) - { - if (sr->that.has_client_wildcard) - { - if (!subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - } - else - { - if (!samesubnet(&sr->that.client, peer_net) && !is_virtual_connection(d)) - { - continue; - } - if (is_virtual_connection(d) - && (!is_virtual_net_allowed(d, peer_net, &c->spd.that.host_addr) - || is_virtual_net_used(peer_net, peer_id?peer_id:c->spd.that.id))) - { - continue; - } - } - } - else - { - host_t *vip = c->spd.that.host_srcip; - - if (!peer_net_is_host && !(sr->that.modecfg && c->spd.that.modecfg && - subnetisaddr(peer_net, (ip_address*)vip->get_sockaddr(vip)))) - { - continue; - } - } - - /* We've run the gauntlet -- success: - * We've got an exact match of subnets. - * The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * routed(sr->routing) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen) - + 1; - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - if (best && NEVER_NEGOTIATE(best->policy)) - { - best = NULL; - } - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; -} - -static connection_t *fc_try_oppo(const connection_t *c, - struct host_pair *hp, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port, - identification_t *peer_ca, - ietf_attributes_t *peer_attributes) -{ - connection_t *d; - connection_t *best = NULL; - policy_prio_t best_prio = BOTTOM_PRIO; - id_match_t match_level; - int pathlen; - - for (d = hp->connections; d != NULL; d = d->hp_next) - { - struct spd_route *sr; - policy_prio_t prio; - - if (d->policy & POLICY_GROUP) - { - continue; - } - match_level = c->spd.that.id->matches(c->spd.that.id, c->spd.that.id); - - if (!(c->spd.this.id->equals(c->spd.this.id, d->spd.this.id) && - (match_level > ID_MATCH_NONE) && - trusted_ca(peer_ca, d->spd.that.ca, &pathlen) && - match_group_membership(peer_attributes, d->name, d->spd.that.groups))) - { - continue; - } - - /* compare protocol and ports */ - if (d->spd.this.protocol != our_protocol - || d->spd.this.port != our_port - || d->spd.that.protocol != peer_protocol - || (d->spd.that.port != peer_port && !d->spd.that.has_port_wildcard)) - { - continue; - } - - /* Opportunistic case: - * our_net must be inside d->spd.this.client - * and peer_net must be inside d->spd.that.client - * Note: this host_pair chain also has shunt - * eroute conns (clear, drop), but they won't - * be marked as opportunistic. - */ - for (sr = &d->spd; sr != NULL; sr = sr->next) - { -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - char s3[SUBNETTOT_BUF],d3[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - subnettot(&sr->this.client, 0, s3, sizeof(s3)); - subnettot(&sr->that.client, 0, d3, sizeof(d3)); - DBG_log(" fc_try_oppo trying %s:%s -> %s vs %s:%s -> %s" - , c->name, s1, d1, d->name, s3, d3); - } -#endif /* DEBUG */ - - if (!subnetinsubnet(our_net, &sr->this.client) - || !subnetinsubnet(peer_net, &sr->that.client)) - { - continue; - } - - /* The connection is feasible, but we continue looking for the best. - * The highest priority wins, implementing eroute-like rule. - * - our smallest client subnet is preferred (longest mask) - * - given that, his smallest client subnet is preferred - * - given that, a routed connection is preferrred - * - given that, the smallest number of ID wildcards are preferred - * - given that, the shortest CA pathlength is preferred - */ - prio = PRIO_WEIGHT * (d->prio + routed(sr->routing)) - + WILD_WEIGHT * match_level - + PATH_WEIGHT * (X509_MAX_PATH_LEN - pathlen); - if (prio > best_prio) - { - best = d; - best_prio = prio; - } - } - } - - /* if the best wasn't opportunistic, we fail: it must be a shunt */ - if (best && (NEVER_NEGOTIATE(best->policy) || - (best->policy & POLICY_OPPO) == LEMPTY)) - { - best = NULL; - } - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try_oppo concluding with %s [%ld]" - , (best ? best->name : "none"), best_prio) - ) - return best; - -} - -/* - * get the peer's CA and group attributes - */ -void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes) -{ - struct state *p1st; - - *peer_ca = NULL; - *peer_attributes = NULL; - - p1st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st && p1st->st_peer_pubkey && p1st->st_peer_pubkey->issuer) - { - certificate_t *cert; - - cert = ac_get_cert(p1st->st_peer_pubkey->issuer, - p1st->st_peer_pubkey->serial); - if (cert && ac_verify_cert(cert, strict_crl_policy)) - { - ac_t *ac = (ac_t*)cert; - - *peer_attributes = ac->get_groups(ac); - } - else - { - DBG(DBG_CONTROL, - DBG_log("no valid attribute cert found") - ) - } - *peer_ca = p1st->st_peer_pubkey->issuer; - } -} - -connection_t *find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t our_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port) -{ - connection_t *d; - struct spd_route *sr; - ietf_attributes_t *peer_attributes = NULL; - identification_t *peer_ca; - - get_peer_ca_and_groups(c, &peer_ca, &peer_attributes); - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s1[SUBNETTOT_BUF],d1[SUBNETTOT_BUF]; - - subnettot(our_net, 0, s1, sizeof(s1)); - subnettot(peer_net, 0, d1, sizeof(d1)); - - DBG_log("find_client_connection starting with %s" - , (c ? c->name : "(none)")); - DBG_log(" looking for %s:%d/%d -> %s:%d/%d" - , s1, our_protocol, our_port - , d1, peer_protocol, peer_port); - } -#endif /* DEBUG */ - - /* give priority to current connection - * but even greater priority to a routed concrete connection - */ - { - connection_t *unrouted = NULL; - int srnum = -1; - - for (sr = &c->spd; unrouted == NULL && sr != NULL; sr = sr->next) - { - srnum++; - -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - DBG_log(" concrete checking against sr#%d %s -> %s" - , srnum, s2, d2); - } -#endif /* DEBUG */ - - if (samesubnet(&sr->this.client, our_net) - && samesubnet(&sr->that.client, peer_net) - && sr->this.protocol == our_protocol - && sr->this.port == our_port - && sr->that.protocol == peer_protocol - && sr->that.port == peer_port - && match_group_membership(peer_attributes, c->name, sr->that.groups)) - { - passert(oriented(*c)); - if (routed(sr->routing)) - { - DESTROY_IF(peer_attributes); - return c; - } - unrouted = c; - } - } - - /* exact match? */ - d = fc_try(c, c->host_pair, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - DBG(DBG_CONTROLMORE, - DBG_log(" fc_try %s gives %s" - , c->name - , (d ? d->name : "none")) - ) - - if (d == NULL) - { - d = unrouted; - } - } - - if (d == NULL) - { - /* look for an abstract connection to match */ - struct spd_route *sr; - struct host_pair *hp = NULL; - - for (sr = &c->spd; hp==NULL && sr != NULL; sr = sr->next) - { - hp = find_host_pair(&sr->this.host_addr - , sr->this.host_port - , NULL - , sr->that.host_port); -#ifdef DEBUG - if (DBGP(DBG_CONTROLMORE)) - { - char s2[SUBNETTOT_BUF],d2[SUBNETTOT_BUF]; - - subnettot(&sr->this.client, 0, s2, sizeof(s2)); - subnettot(&sr->that.client, 0, d2, sizeof(d2)); - - DBG_log(" checking hostpair %s -> %s is %s" - , s2, d2 - , (hp ? "found" : "not found")); - } -#endif /* DEBUG */ - } - - if (hp) - { - /* RW match with actual peer_id or abstract peer_id? */ - d = fc_try(c, hp, NULL, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - - if (d == NULL - && subnetishost(our_net) - && subnetishost(peer_net)) - { - /* Opportunistic match? - * Always use abstract peer_id. - * Note that later instantiation will result in the same peer_id. - */ - d = fc_try_oppo(c, hp, our_net, peer_net - , our_protocol, our_port, peer_protocol, peer_port - , peer_ca, peer_attributes); - } - } - } - - DBG(DBG_CONTROLMORE, - DBG_log(" concluding with d = %s" - , (d ? d->name : "none")) - ) - DESTROY_IF(peer_attributes); - return d; -} - -int connection_compare(const connection_t *ca, const connection_t *cb) -{ - int ret; - - /* DBG_log("comparing %s to %s", ca->name, cb->name); */ - - ret = strcasecmp(ca->name, cb->name); - if (ret) - { - return ret; - } - - ret = ca->kind - cb->kind; /* note: enum connection_kind behaves like int */ - if (ret) - { - return ret; - } - - /* same name, and same type */ - switch (ca->kind) - { - case CK_INSTANCE: - return ca->instance_serial < cb->instance_serial ? -1 - : ca->instance_serial > cb->instance_serial ? 1 - : 0; - - default: - return ca->prio < cb->prio ? -1 - : ca->prio > cb->prio ? 1 - : 0; - } -} - -static int connection_compare_qsort(const void *a, const void *b) -{ - return connection_compare(*(const connection_t *const *)a - , *(const connection_t *const *)b); -} - -void show_connections_status(bool all, const char *name) -{ - connection_t *c; - int count, i; - connection_t **array; - - /* make an array of connections, and sort it */ - count = 0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - count++; - } - array = malloc(sizeof(connection_t *)*count); - - count=0; - for (c = connections; c != NULL; c = c->ac_next) - { - if (c->ikev1 && (name == NULL || streq(c->name, name))) - array[count++]=c; - } - - /* sort it! */ - qsort(array, count, sizeof(connection_t *), connection_compare_qsort); - - for (i = 0; i < count; i++) - { - const char *ifn; - char instance[1 + 10 + 1]; - char prio[POLICY_PRIO_BUF]; - - c = array[i]; - - ifn = oriented(*c)? c->interface->rname : ""; - - instance[0] = '\0'; - if (c->kind == CK_INSTANCE && c->instance_serial != 0) - snprintf(instance, sizeof(instance), "[%lu]", c->instance_serial); - - /* show topology */ - { - char topo[BUF_LEN]; - struct spd_route *sr = &c->spd; - int num=0; - - while (sr) - { - (void) format_connection(topo, sizeof(topo), c, sr); - whack_log(RC_COMMENT, "\"%s\"%s: %s; %s; eroute owner: #%lu" - , c->name, instance, topo - , enum_name(&routing_story, sr->routing) - , sr->eroute_owner); - sr = sr->next; - num++; - } - } - - if (all) - { - /* show CAs if defined */ - if (c->spd.this.ca && c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...\"%Y\"", - c->name, instance, c->spd.this.ca, c->spd.that.ca); - } - else if (c->spd.this.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: \"%Y\"...%%any", - c->name, instance, c->spd.this.ca); - - } - else if (c->spd.that.ca) - { - whack_log(RC_COMMENT, "\"%s\"%s: CAs: %%any...\"%Y\"", - c->name, instance, c->spd.that.ca); - } - - /* show group attributes if defined */ - if (c->spd.that.groups) - { - whack_log(RC_COMMENT, "\"%s\"%s: groups: %s" - , c->name - , instance - , c->spd.that.groups->get_string(c->spd.that.groups)); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: ike_life: %lus; ipsec_life: %lus;" - " rekey_margin: %lus; rekey_fuzz: %lu%%; keyingtries: %lu" - , c->name - , instance - , (unsigned long) c->sa_ike_life_seconds - , (unsigned long) c->sa_ipsec_life_seconds - , (unsigned long) c->sa_rekey_margin - , (unsigned long) c->sa_rekey_fuzz - , (unsigned long) c->sa_keying_tries); - - /* show DPD parameters if defined */ - - if (c->dpd_action != DPD_ACTION_NONE) - whack_log(RC_COMMENT - , "\"%s\"%s: dpd_action: %N;" - " dpd_delay: %lus; dpd_timeout: %lus;" - , c->name - , instance - , dpd_action_names, c->dpd_action - , (unsigned long) c->dpd_delay - , (unsigned long) c->dpd_timeout); - - if (c->policy_next) - { - whack_log(RC_COMMENT - , "\"%s\"%s: policy_next: %s" - , c->name, instance, c->policy_next->name); - } - - /* Note: we display key_from_DNS_on_demand as if policy [lr]KOD */ - fmt_policy_prio(c->prio, prio); - whack_log(RC_COMMENT - , "\"%s\"%s: policy: %s%s%s; prio: %s; interface: %s; " - , c->name - , instance - , prettypolicy(c->policy) - , c->spd.this.key_from_DNS_on_demand? "+lKOD" : "" - , c->spd.that.key_from_DNS_on_demand? "+rKOD" : "" - , prio - , ifn); - } - - whack_log(RC_COMMENT - , "\"%s\"%s: newest ISAKMP SA: #%ld; newest IPsec SA: #%ld; " - , c->name - , instance - , c->newest_isakmp_sa - , c->newest_ipsec_sa); - - if (all) - { - ike_alg_show_connection(c, instance); - kernel_alg_show_connection(c, instance); - } - } - if (count > 0) - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - - free(array); -} - -/* struct pending, the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - * Essentially, a pending call to quick_outI1. - */ - -struct pending { - int whack_sock; - struct state *isakmp_sa; - connection_t *connection; - lset_t policy; - unsigned long try; - so_serial_t replacing; - - struct pending *next; -}; - -/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */ -void add_pending(int whack_sock, struct state *isakmp_sa, connection_t *c, - lset_t policy, unsigned long try, so_serial_t replacing) -{ - bool already_queued = FALSE; - struct pending *p = c->host_pair->pending; - - while (p) - { - if (streq(c->name, p->connection->name)) - { - already_queued = TRUE; - break; - } - p = p->next; - } - DBG(DBG_CONTROL, - DBG_log("Queuing pending Quick Mode with %s \"%s\"%s" - , ip_str(&c->spd.that.host_addr) - , c->name - , already_queued? " already done" : "") - ) - if (already_queued) - return; - - p = malloc_thing(struct pending); - p->whack_sock = whack_sock; - p->isakmp_sa = isakmp_sa; - p->connection = c; - p->policy = policy; - p->try = try; - p->replacing = replacing; - p->next = c->host_pair->pending; - c->host_pair->pending = p; -} - -/* Release all the whacks awaiting the completion of this state. - * This is accomplished by closing all the whack socket file descriptors. - * We go to a lot of trouble to tell each whack, but to not tell it twice. - */ -void release_pending_whacks(struct state *st, err_t story) -{ - struct pending *p; - struct stat stst; - - if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0) - zero(&stst); /* resulting st_dev/st_ino ought to be distinct */ - - release_whack(st); - - for (p = st->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st && p->whack_sock != NULL_FD) - { - struct stat pst; - - if (fstat(p->whack_sock, &pst) == 0 - && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino)) - { - passert(whack_log_fd == NULL_FD); - whack_log_fd = p->whack_sock; - whack_log(RC_COMMENT - , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA" - , story); - whack_log_fd = NULL_FD; - } - close(p->whack_sock); - p->whack_sock = NULL_FD; - } - } -} - -static void delete_pending(struct pending **pp) -{ - struct pending *p = *pp; - - *pp = p->next; - if (p->connection) - { - connection_discard(p->connection); - } - close_any(p->whack_sock); - free(p); -} - -void unpend(struct state *st) -{ - struct pending **pp - , *p; - - for (pp = &st->st_connection->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - { - DBG(DBG_CONTROL, DBG_log("unqueuing pending Quick Mode with %s \"%s\"" - , ip_str(&p->connection->spd.that.host_addr) - , p->connection->name)); - (void) quick_outI1(p->whack_sock, st, p->connection, p->policy - , p->try, p->replacing); - p->whack_sock = NULL_FD; /* ownership transferred */ - p->connection = NULL; /* ownership transferred */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } -} - -/* a Main Mode negotiation has been replaced; update any pending */ -void update_pending(struct state *os, struct state *ns) -{ - struct pending *p; - - for (p = os->st_connection->host_pair->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == os) - p->isakmp_sa = ns; - if (p->connection->spd.this.host_port != ns->st_connection->spd.this.host_port) - { - p->connection->spd.this.host_port = ns->st_connection->spd.this.host_port; - p->connection->spd.that.host_port = ns->st_connection->spd.that.host_port; - } - } -} - -/* a Main Mode negotiation has failed; discard any pending */ -void flush_pending_by_state(struct state *st) -{ - struct host_pair *hp = st->st_connection->host_pair; - - if (hp) - { - struct pending **pp - , *p; - - for (pp = &hp->pending; (p = *pp) != NULL; ) - { - if (p->isakmp_sa == st) - delete_pending(pp); - else - pp = &p->next; - } - } -} - -/* a connection has been deleted; discard any related pending */ -static void flush_pending_by_connection(connection_t *c) -{ - if (c->host_pair) - { - struct pending **pp - , *p; - - for (pp = &c->host_pair->pending; (p = *pp) != NULL; ) - { - if (p->connection == c) - { - p->connection = NULL; /* prevent delete_pending from releasing */ - delete_pending(pp); - } - else - { - pp = &p->next; - } - } - } -} - -void show_pending_phase2(const struct host_pair *hp, const struct state *st) -{ - const struct pending *p; - - for (p = hp->pending; p != NULL; p = p->next) - { - if (p->isakmp_sa == st) - { - /* connection-name state-number [replacing state-number] */ - char cip[CONN_INST_BUF]; - - fmt_conn_instance(p->connection, cip); - whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu" - , p->isakmp_sa->st_serialno - , p->connection->name - , cip - , p->replacing); - } - } -} - -/* Delete a connection if it is an instance and it is no longer in use. - * We must be careful to avoid circularity: - * we don't touch it if it is CK_GOING_AWAY. - */ -void connection_discard(connection_t *c) -{ - if (c->kind == CK_INSTANCE) - { - /* see if it is being used by a pending */ - struct pending *p; - - for (p = c->host_pair->pending; p != NULL; p = p->next) - if (p->connection == c) - return; /* in use, so we're done */ - - if (!states_use_connection(c)) - delete_connection(c, FALSE); - } -} - - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ - -long eclipse_count = 0; - -connection_t *eclipsed(connection_t *c, struct spd_route **esrp) -{ - connection_t *ue; - struct spd_route *sr1 = &c->spd; - - ue = NULL; - - while (sr1 && ue) - { - for (ue = connections; ue != NULL; ue = ue->ac_next) - { - struct spd_route *srue = &ue->spd; - - while (srue && srue->routing == RT_ROUTED_ECLIPSED - && !(samesubnet(&sr1->this.client, &srue->this.client) - && samesubnet(&sr1->that.client, &srue->that.client))) - { - srue = srue->next; - } - if (srue && srue->routing == RT_ROUTED_ECLIPSED) - { - *esrp = srue; - break; - } - } - } - return ue; -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/connections.h b/src/pluto/connections.h deleted file mode 100644 index e3775fcb0..000000000 --- a/src/pluto/connections.h +++ /dev/null @@ -1,366 +0,0 @@ -/* information about connections between hosts and clients - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * Copyright (C) 2009-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONNECTIONS_H -#define _CONNECTIONS_H - -#include - -#include -#include -#include -#include - -#include "certs.h" -#include "smartcard.h" -#include "whack.h" - -/* There are two kinds of connections: - * - ISAKMP connections, between hosts (for IKE communication) - * - IPsec connections, between clients (for secure IP communication) - * - * An ISAKMP connection looks like: - * host<--->host - * - * An IPsec connection looks like: - * client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet - * - * For the connection to be relevant to this instance of Pluto, - * exactly one of the hosts must be a public interface of our machine - * known to this instance. - * - * The client subnet might simply be the host -- this is a - * representation of "host mode". - * - * Each nexthop defaults to the neighbouring host's IP address. - * The nexthop is a property of the pair of hosts, not each - * individually. It is only needed for IPsec because of the - * way IPsec is mixed into the kernel routing logic. Furthermore, - * only this end's nexthop is actually used. Eventually, nexthop - * will be unnecessary. - * - * Other information represented: - * - each connection has a name: a chunk of uninterpreted text - * that is unique for each connection. - * - security requirements (currently just the "policy" flags from - * the whack command to initiate the connection, but eventually - * much more. Different for ISAKMP and IPsec connections. - * - rekeying parameters: - * + time an SA may live - * + time before SA death that a rekeying should be attempted - * (only by the initiator) - * + number of times to attempt rekeying - * - With the current KLIPS, we must route packets for a client - * subnet through the ipsec interface (ipsec0). Only one - * gateway can get traffic for a specific (client) subnet. - * Furthermore, if the routing isn't in place, packets will - * be sent in the clear. - * "routing" indicates whether the routing has been done for - * this connection. Note that several connections may claim - * the same routing, as long as they agree about where the - * packets are to be sent. - * - With the current KLIPS, only one outbound IPsec SA bundle can be - * used for a particular client. This is due to a limitation - * of using only routing for selection. So only one IPsec state (SA) - * may "own" the eroute. "eroute_owner" is the serial number of - * this state, SOS_NOBODY if there is none. "routing" indicates - * what kind of erouting has been done for this connection, if any. - * - * Details on routing is in constants.h - * - * Operations on Connections: - * - * - add a new connection (with all details) [whack command] - * - delete a connection (by name) [whack command] - * - initiate a connection (by name) [whack command] - * - find a connection (by IP addresses of hosts) - * [response to peer request; finding ISAKMP connection for IPsec connection] - * - * Some connections are templates, missing the address of the peer - * (represented by INADDR_ANY). These are always arranged so that the - * missing end is "that" (there can only be one missing end). These can - * be instantiated (turned into real connections) by Pluto in one of two - * different ways: Road Warrior Instantiation or Opportunistic - * Instantiation. A template connection is marked for Opportunistic - * Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6 - * equivalent). Otherwise, it is suitable for Road Warrior Instantiation. - * - * Instantiation creates a new temporary connection, with the missing - * details filled in. The resulting template lasts only as long as there - * is a state that uses it. - */ - -/* connection policy priority: how important this policy is - * - used to implement eroute-like precedence (augmented by a small - * bonus for a routed connection). - * - a whole number - * - larger is more important - * - three subcomponents. In order of decreasing significance: - * + length of source subnet mask (8 bits) - * + length of destination subnet mask (8 bits) - * + bias (8 bit) - * - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all - * normal priorities - * - other bias values are created on the fly to give mild preference - * to certaion conditions (eg. routedness) - * - priority is inherited -- an instance of a policy has the same priority - * as the original policy, even though its subnets might be smaller. - * - display format: n,m - */ -typedef unsigned long policy_prio_t; -#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */ -#define set_policy_prio(c) { (c)->prio = \ - ((policy_prio_t)(c)->spd.this.client.maskbits << 16) \ - | ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \ - | (policy_prio_t)1; } -#define POLICY_PRIO_BUF (3+1+3+1) -extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]); - -struct virtual_t; - -struct end { - identification_t *id; - ip_address host_addr, host_nexthop; - host_t *host_srcip; - ip_subnet client; - - bool is_left; - bool key_from_DNS_on_demand; - bool has_client; - bool has_client_wildcard; - bool has_port_wildcard; - bool has_id_wildcards; - bool has_natip; - char *updown; - u_int16_t host_port; /* host order */ - u_int16_t port; /* host order */ - u_int8_t protocol; - cert_t *cert; /* end certificate */ - identification_t *ca; /* CA distinguished name */ - ietf_attributes_t *groups; /* access control groups */ - smartcard_t *sc; /* smartcard reader and key info */ - struct virtual_t *virt; - bool modecfg; /* this end: request local address from server */ - /* that end: give local addresses to clients */ - char *pool; /* name of an associated virtual IP address pool */ - bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */ - /* rules if client behind host is a subnet */ - bool allow_any; /* IP address is subject to change */ - certpolicy_t sendcert; /* whether or not to send the certificate */ -}; - -struct spd_route { - struct spd_route *next; - struct end this; - struct end that; - so_serial_t eroute_owner; - enum routing_t routing; /* level of routing in place */ - uint32_t reqid; - mark_t mark_in; - mark_t mark_out; -}; - -typedef struct connection connection_t; - -struct connection { - char *name; - bool ikev1; - - lset_t policy; - time_t sa_ike_life_seconds; - time_t sa_ipsec_life_seconds; - time_t sa_rekey_margin; - unsigned long sa_rekey_fuzz; - unsigned long sa_keying_tries; - - identification_t *xauth_identity; /* XAUTH identity */ - - /* RFC 3706 DPD */ - time_t dpd_delay; - time_t dpd_timeout; - dpd_action_t dpd_action; - - char *log_file_name; /* name of log file */ - FILE *log_file; /* possibly open FILE */ - TAILQ_ENTRY(connection) log_link; /* linked list of open conns */ - bool log_file_err; /* only bitch once */ - - struct spd_route spd; - - /* internal fields: */ - - unsigned long instance_serial; - policy_prio_t prio; - bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */ - enum connection_kind kind; - const struct iface *interface; /* filled in iff oriented */ - - so_serial_t /* state object serial number */ - newest_isakmp_sa, - newest_ipsec_sa; - - -#ifdef DEBUG - lset_t extra_debugging; -#endif - - /* note: if the client is the gateway, the following must be equal */ - sa_family_t addr_family; /* between gateways */ - sa_family_t tunnel_addr_family; /* between clients */ - - connection_t *policy_next; /* if multiple policies, - next one to apply */ - struct gw_info *gw_info; - struct alg_info_esp *alg_info_esp; - struct alg_info_ike *alg_info_ike; - struct host_pair *host_pair; - connection_t *hp_next; /* host pair list link */ - connection_t *ac_next; /* all connections list link */ - linked_list_t *requested_ca; /* collected certificate requests */ - linked_list_t *requested; /* requested attributes with handlers */ - linked_list_t *attributes; /* configuration attributes with handlers */ - bool got_certrequest; -}; - -#define oriented(c) ((c).interface != NULL) -extern bool orient(connection_t *c); - -extern bool same_peer_ids(const connection_t *c, const connection_t *d, - identification_t *his_id); - -/* Format the topology of a connection end, leaving out defaults. - * Largest left end looks like: client === host : port [ host_id ] --- hop - * Note: if that==NULL, skip nexthop - */ -#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10) -extern size_t format_end(char *buf, size_t buf_len, const struct end *this, - const struct end *that, bool is_left, lset_t policy); - -extern void add_connection(const whack_message_t *wm); -extern void initiate_connection(const char *name, int whackfd); -extern void initiate_opportunistic(const ip_address *our_client, - const ip_address *peer_client, - int transport_proto, bool held, int whackfd); -extern void terminate_connection(const char *nm); -extern void release_connection(connection_t *c, bool relations); -extern void delete_connection(connection_t *c, bool relations); -extern void delete_connections_by_name(const char *name, bool strict); -extern void delete_every_connection(void); -extern char *add_group_instance(connection_t *group, const ip_subnet *target); -extern void remove_group_instance(const connection_t *group, const char *name); -extern void release_dead_interfaces(void); -extern void check_orientations(void); -extern connection_t *route_owner(connection_t *c, struct spd_route **srp, - connection_t **erop, struct spd_route **esrp); -extern connection_t *shunt_owner(const ip_subnet *ours, const ip_subnet *his); - -extern bool uniqueIDs; /* --uniqueids? */ -extern void ISAKMP_SA_established(connection_t *c, so_serial_t serial); - -#define id_is_ipaddr(id) ((id)->get_type(id) == ID_IPV4_ADDR || \ - (id)->get_type(id) == ID_IPV6_ADDR) -extern bool his_id_was_instantiated(const connection_t *c); - -struct state; /* forward declaration of tag (defined in state.h) */ - -extern connection_t* con_by_name(const char *nm, bool strict); -extern connection_t* find_host_connection(const ip_address *me, - u_int16_t my_port, - const ip_address *him, - u_int16_t his_port, lset_t policy); -extern connection_t* refine_host_connection(const struct state *st, - identification_t *id, - identification_t *peer_ca); -extern connection_t* find_client_connection(connection_t *c, - const ip_subnet *our_net, - const ip_subnet *peer_net, - const u_int8_t our_protocol, - const u_int16_t out_port, - const u_int8_t peer_protocol, - const u_int16_t peer_port); -extern connection_t* find_connection_by_reqid(uint32_t reqid); -extern connection_t* find_connection_for_clients(struct spd_route **srp, - const ip_address *our_client, - const ip_address *peer_client, - int transport_proto); -extern void get_peer_ca_and_groups(connection_t *c, - identification_t **peer_ca, - ietf_attributes_t **peer_attributes); - -/* instantiating routines - * Note: connection_discard() is in state.h because all its work - * is looking through state objects. - */ -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -struct alg_info; /* forward declaration of tag (defined in alg_info.h) */ -extern connection_t *rw_instantiate(connection_t *c, - const ip_address *him, - u_int16_t his_port, - const ip_subnet *his_net, - identification_t *his_id); - -extern connection_t *oppo_instantiate(connection_t *c, - const ip_address *him, - identification_t *his_id, - struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -extern connection_t - *build_outgoing_opportunistic_connection(struct gw_info *gw, - const ip_address *our_client, - const ip_address *peer_client); - -#define CONN_INST_BUF BUF_LEN - -extern void fmt_conn_instance(const connection_t *c, char buf[CONN_INST_BUF]); - -/* operations on "pending", the structure representing Quick Mode - * negotiations delayed until a Keying Channel has been negotiated. - */ - -struct pending; /* forward declaration (opaque outside connections.c) */ - -extern void add_pending(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing); - -extern void release_pending_whacks(struct state *st, err_t story); -extern void unpend(struct state *st); -extern void update_pending(struct state *os, struct state *ns); -extern void flush_pending_by_state(struct state *st); -extern void show_pending_phase2(const struct host_pair *hp, const struct state *st); - -extern void connection_discard(connection_t *c); - -/* A template connection's eroute can be eclipsed by - * either a %hold or an eroute for an instance iff - * the template is a /32 -> /32. This requires some special casing. - */ -#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client)) -extern long eclipse_count; -extern connection_t *eclipsed(connection_t *c, struct spd_route **); - - -/* print connection status */ - -extern void show_connections_status(bool all, const char *name); -extern int connection_compare(const connection_t *ca - , const connection_t *cb); -extern void update_host_pair(const char *why, connection_t *c - , const ip_address *myaddr, u_int16_t myport - , const ip_address *hisaddr, u_int16_t hisport); - -#endif /* _CONNECTIONS_H */ diff --git a/src/pluto/constants.c b/src/pluto/constants.c deleted file mode 100644 index 73ec0bc54..000000000 --- a/src/pluto/constants.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* tables of names for values defined in constants.h - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * Note that the array sizes are all specified; this is to enable range - * checking by code that only includes constants.h. - */ - -#include -#include -#include -#include - -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" - -/* string naming compile-time options that have interop implications */ - -const char compile_time_interop_options[] = "" -#ifdef THREADS - " THREADS" -#endif -#ifdef SMARTCARD - " SMARTCARD" -#endif -#ifdef VENDORID - " VENDORID" -#endif -#ifdef CISCO_QUIRKS - " CISCO_QUIRKS" -#endif -#ifdef USE_KEYRR - " KEYRR" -#endif - ; - -/* version */ - -static const char *const version_name[] = { - "ISAKMP Version 1.0", -}; - -enum_names version_names = - { ISAKMP_MAJOR_VERSION< - -static const char *const rr_type_name[] = { - "T_A", /* 1 host address */ - "T_NS", /* 2 authoritative server */ - "T_MD", /* 3 mail destination */ - "T_MF", /* 4 mail forwarder */ - "T_CNAME", /* 5 canonical name */ - "T_SOA", /* 6 start of authority zone */ - "T_MB", /* 7 mailbox domain name */ - "T_MG", /* 8 mail group member */ - "T_MR", /* 9 mail rename name */ - "T_NULL", /* 10 null resource record */ - "T_WKS", /* 11 well known service */ - "T_PTR", /* 12 domain name pointer */ - "T_HINFO", /* 13 host information */ - "T_MINFO", /* 14 mailbox information */ - "T_MX", /* 15 mail routing information */ - "T_TXT", /* 16 text strings */ - "T_RP", /* 17 responsible person */ - "T_AFSDB", /* 18 AFS cell database */ - "T_X25", /* 19 X_25 calling address */ - "T_ISDN", /* 20 ISDN calling address */ - "T_RT", /* 21 router */ - "T_NSAP", /* 22 NSAP address */ - "T_NSAP_PTR", /* 23 reverse NSAP lookup (deprecated) */ - "T_SIG", /* 24 security signature */ - "T_KEY", /* 25 security key */ - "T_PX", /* 26 X.400 mail mapping */ - "T_GPOS", /* 27 geographical position (withdrawn) */ - "T_AAAA", /* 28 IP6 Address */ - "T_LOC", /* 29 Location Information */ - "T_NXT", /* 30 Next Valid Name in Zone */ - "T_EID", /* 31 Endpoint identifier */ - "T_NIMLOC", /* 32 Nimrod locator */ - "T_SRV", /* 33 Server selection */ - "T_ATMA", /* 34 ATM Address */ - "T_NAPTR", /* 35 Naming Authority PoinTeR */ - NULL -}; - -enum_names rr_type_names = { T_A, T_NAPTR, rr_type_name, NULL }; - -/* Query type values which do not appear in resource records */ -static const char *const rr_qtype_name[] = { - "T_IXFR", /* 251 incremental zone transfer */ - "T_AXFR", /* 252 transfer zone of authority */ - "T_MAILB", /* 253 transfer mailbox records */ - "T_MAILA", /* 254 transfer mail agent records */ - "T_ANY", /* 255 wildcard match */ - NULL -}; - -enum_names rr_qtype_names = { T_IXFR, T_ANY, rr_qtype_name, &rr_type_names }; - -static const char *const rr_class_name[] = { - "C_IN", /* 1 the arpa internet */ - NULL -}; - -enum_names rr_class_names = { C_IN, C_IN, rr_class_name, NULL }; - -#endif /* ADNS */ - -/* - * NAT-Traversal defines for nat_traveral type from nat_traversal.h - * - */ -const char *const natt_type_bitnames[] = { - "draft-ietf-ipsec-nat-t-ike-00/01", /* 0 */ - "draft-ietf-ipsec-nat-t-ike-02/03", - "RFC 3947", - "3", /* 3 */ - "4", "5", "6", "7", - "8", "9", "10", "11", - "12", "13", "14", "15", - "16", "17", "18", "19", - "20", "21", "22", "23", - "24", "25", "26", "27", - "28", "29", - "nat is behind me", - "nat is behind peer" -}; - -/* look up enum names in an enum_names */ - -const char* enum_name(enum_names *ed, unsigned long val) -{ - enum_names *p; - - for (p = ed; p != NULL; p = p->en_next_range) - { - if (p->en_first <= val && val <= p->en_last) - return p->en_names[val - p->en_first]; - } - return NULL; -} - -/* find or construct a string to describe an enum value - * Result may be in STATIC buffer! - */ -const char * -enum_show(enum_names *ed, unsigned long val) -{ - const char *p = enum_name(ed, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - - -static char bitnamesbuf[200]; /* only one! I hope that it is big enough! */ - -int -enum_search(enum_names *ed, const char *str) -{ - enum_names *p; - const char *ptr; - unsigned en; - - for (p = ed; p != NULL; p = p->en_next_range) - { - for (en = p->en_first; en <= p->en_last ;en++) - { - ptr = p->en_names[en - p->en_first]; - if (ptr == 0) - { - continue; - } - if (streq(ptr, str)) - { - return en; - } - } - } - return -1; -} - -/* construct a string to name the bits on in a set - * Result may be in STATIC buffer! - * Note: prettypolicy depends on internal details. - */ -const char* bitnamesof(const char *const table[], lset_t val) -{ - char *p = bitnamesbuf; - lset_t bit; - const char *const *tp; - - if (val == 0) - return "none"; - - for (tp = table, bit = 01; val != 0; bit <<= 1) - { - if (val & bit) - { - const char *n = *tp; - size_t nl; - - if (n == NULL || *n == '\0') - { - /* no name for this bit, so use hex */ - static char flagbuf[sizeof("0x80000000")]; - - snprintf(flagbuf, sizeof(flagbuf), "0x%llx", bit); - n = flagbuf; - } - - nl = strlen(n); - - if (p != bitnamesbuf && p < bitnamesbuf+sizeof(bitnamesbuf) - 1) - *p++ = '+'; - - if (bitnamesbuf+sizeof(bitnamesbuf) - p > (ptrdiff_t)nl) - { - strcpy(p, n); - p += nl; - } - val -= bit; - } - if (*tp != NULL) - tp++; /* move on, but not past end */ - } - *p = '\0'; - return bitnamesbuf; -} - -/* print a policy: like bitnamesof, but it also does the non-bitfields. - * Suppress the shunt and fail fields if 0. - */ -const char* prettypolicy(lset_t policy) -{ - const char *bn = bitnamesof(sa_policy_bit_names - , policy & ~(POLICY_SHUNT_MASK | POLICY_FAIL_MASK)); - size_t len; - lset_t shunt = (policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT; - lset_t fail = (policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT; - - if (bn != bitnamesbuf) - bitnamesbuf[0] = '\0'; - len = strlen(bitnamesbuf); - if (shunt != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+%s" - , policy_shunt_names[shunt]); - len += strlen(bitnamesbuf + len); - } - if (fail != 0) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+failure%s" - , policy_fail_names[fail]); - len += strlen(bitnamesbuf + len); - } - if (NEVER_NEGOTIATE(policy)) - { - snprintf(bitnamesbuf + len, sizeof(bitnamesbuf) - len, "+NEVER_NEGOTIATE"); - len += strlen(bitnamesbuf + len); - } - return bitnamesbuf; -} - -/* test a set by seeing if all bits have names */ - -bool testset(const char *const table[], lset_t val) -{ - lset_t bit; - const char *const *tp; - - for (tp = table, bit = 01; val != 0; bit <<= 1, tp++) - { - const char *n = *tp; - - if (n == NULL || ((val & bit) && *n == '\0')) - return FALSE; - val &= ~bit; - } - return TRUE; -} - - -const char sparse_end[] = "end of sparse names"; - -/* look up enum names in a sparse_names */ -const char *sparse_name(sparse_names sd, unsigned long val) -{ - const struct sparse_name *p; - - for (p = sd; p->name != sparse_end; p++) - if (p->val == val) - return p->name; - return NULL; -} - -/* find or construct a string to describe an sparse value - * Result may be in STATIC buffer! - */ -const char* sparse_val_show(sparse_names sd, unsigned long val) -{ - const char *p = sparse_name(sd, val); - - if (p == NULL) - { - static char buf[12]; /* only one! I hope that it is big enough */ - - snprintf(buf, sizeof(buf), "%lu??", val); - p = buf; - } - return p; -} - -void init_constants(void) -{ - happy(anyaddr(AF_INET, &ipv4_any)); - happy(anyaddr(AF_INET6, &ipv6_any)); - - happy(addrtosubnet(&ipv4_any, &ipv4_wildcard)); - happy(addrtosubnet(&ipv6_any, &ipv6_wildcard)); - - happy(initsubnet(&ipv4_any, 0, '0', &ipv4_all)); - happy(initsubnet(&ipv6_any, 0, '0', &ipv6_all)); -} - -u_char secret_of_the_day[HASH_SIZE_SHA1]; - - diff --git a/src/pluto/constants.h b/src/pluto/constants.h deleted file mode 100644 index c931f1782..000000000 --- a/src/pluto/constants.h +++ /dev/null @@ -1,1099 +0,0 @@ -/* manifest constants - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _CONSTANTS_H -#define _CONSTANTS_H - -#include - -#include - -#include -#include -#include - -extern const char compile_time_interop_options[]; - -extern void init_constants(void); - -/* - * NOTE:For debugging purposes, constants.c has tables to map numbers back to names. - * Any changes here should be reflected there. - */ - -/* Many routines return only success or failure, but wish to describe - * the failure in a message. We use the convention that they return - * a NULL on success and a pointer to constant string on failure. - * The fact that the string is a constant is limiting, but it - * avoids storage management issues: the recipient is allowed to assume - * that the string will live "long enough" (usually forever). - * defines err_t for this return type. - */ - -#define NULL_FD (-1) /* NULL file descriptor */ -#define dup_any(fd) ((fd) == NULL_FD? NULL_FD : dup(fd)) -#define close_any(fd) { if ((fd) != NULL_FD) { close(fd); (fd) = NULL_FD; } } - -/* set type with room for at least 64 elements for ALG opts (was 32 in stock FS) */ - -typedef unsigned long long lset_t; -#define LEMPTY 0ULL -#define LELEM(opt) (1ULL << (opt)) -#define LRANGE(lwb, upb) LRANGES(LELEM(lwb), LELEM(upb)) -#define LRANGES(first, last) (last - first + last) -#define LHAS(set, elem) ((LELEM(elem) & (set)) != LEMPTY) -#define LIN(subset, set) (((subset) & (set)) == (subset)) -#define LDISJOINT(a, b) (((a) & (b)) == LEMPTY) - -/* Control and lock pathnames */ -#ifndef IPSEC_PIDDIR -# define IPSEC_PIDDIR "/var/run" -#endif -#ifndef DEFAULT_CTLBASE -# define DEFAULT_CTLBASE IPSEC_PIDDIR "/pluto" -#endif - -#define CTL_SUFFIX ".ctl" /* for UNIX domain socket pathname */ -#define LOCK_SUFFIX ".pid" /* for pluto's lock */ -#define INFO_SUFFIX ".info" /* for UNIX domain socket for apps */ - -/* Routines to check and display values. - * - * An enum_names describes an enumeration. - * enum_name() returns the name of an enum value, or NULL if invalid. - * enum_show() is like enum_name, except it formats a numeric representation - * for any invalid value (in a static area!) - * - * bitnames() formats a display of a set of named bits (in a static area) - */ - -struct enum_names { - unsigned long en_first; /* first value in range */ - unsigned long en_last; /* last value in range (inclusive) */ - const char *const *en_names; - const struct enum_names *en_next_range; /* descriptor of next range */ -}; - -typedef const struct enum_names enum_names; - -extern const char *enum_name(enum_names *ed, unsigned long val); -extern const char *enum_show(enum_names *ed, unsigned long val); -extern int enum_search(enum_names *ed, const char *string); - -extern bool testset(const char *const table[], lset_t val); -extern const char *bitnamesof(const char *const table[], lset_t val); - -/* sparse_names is much like enum_names, except values are - * not known to be contiguous or ordered. - * The array of names is ended with one with the name sparse_end - * (this avoids having to reserve a value to signify the end). - * Often appropriate for enums defined by others. - */ -struct sparse_name { - unsigned long val; - const char *const name; -}; -typedef const struct sparse_name sparse_names[]; - -extern const char *sparse_name(sparse_names sd, unsigned long val); -extern const char *sparse_val_show(sparse_names sd, unsigned long val); -extern const char sparse_end[]; - -#define FULL_INET_ADDRESS_SIZE 6 - -/* limits on nonce sizes. See RFC2409 "The internet key exchange (IKE)" 5 */ -#define MINIMUM_NONCE_SIZE 8 /* bytes */ -#define DEFAULT_NONCE_SIZE 16 /* bytes */ -#define MAXIMUM_NONCE_SIZE 256 /* bytes */ - -#define COOKIE_SIZE 8 -#define MAX_ISAKMP_SPI_SIZE 16 - -#define DES_CBC_BLOCK_SIZE (64 / BITS_PER_BYTE) - -/* Maximum is required for SHA2_512 */ -#define MAX_DIGEST_LEN HASH_SIZE_SHA512 - -/* RFC 2404 "HMAC-SHA-1-96" section 3 */ -#define HMAC_SHA1_KEY_LEN HASH_SIZE_SHA1 - -/* RFC 2403 "HMAC-MD5-96" section 3 */ -#define HMAC_MD5_KEY_LEN HASH_SIZE_MD5 - -#define IKE_UDP_PORT 500 - -/* IPsec AH transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.3 - * and in http://www.iana.org/assignments/isakmp-registry - */ -enum ipsec_authentication_algo { - AH_NONE = 0, - AH_MD5 = 2, - AH_SHA = 3, - AH_DES = 4, - AH_SHA2_256 = 5, - AH_SHA2_384 = 6, - AH_SHA2_512 = 7, - AH_RIPEMD = 8, - AH_AES_XCBC_MAC = 9, - AH_RSA = 10, - AH_AES_128_GMAC = 11, - AH_AES_192_GMAC = 12, - AH_AES_256_GMAC = 13, - AH_SHA2_256_96 = 252 -}; - -extern enum_names ah_transform_names; - -/* IPsec ESP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.4 - * and from http://www.iana.org/assignments/isakmp-registry - */ - -enum ipsec_cipher_algo { - ESP_NONE = 0, - ESP_DES_IV64 = 1, - ESP_DES = 2, - ESP_3DES = 3, - ESP_RC5 = 4, - ESP_IDEA = 5, - ESP_CAST = 6, - ESP_BLOWFISH = 7, - ESP_3IDEA = 8, - ESP_DES_IV32 = 9, - ESP_RC4 = 10, - ESP_NULL = 11, - ESP_AES = 12, - ESP_AES_CTR = 13, - ESP_AES_CCM_8 = 14, - ESP_AES_CCM_12 = 15, - ESP_AES_CCM_16 = 16, - ESP_UNASSIGNED_17 = 17, - ESP_AES_GCM_8 = 18, - ESP_AES_GCM_12 = 19, - ESP_AES_GCM_16 = 20, - ESP_SEED_CBC = 21, - ESP_CAMELLIA = 22, - ESP_AES_GMAC = 23, - ESP_SERPENT = 252, - ESP_TWOFISH = 253 -}; - -extern enum_names esp_transform_names; - -/* IPCOMP transform values - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.5 - * now defined in kernel/kernel_ipsec.h - */ - -extern enum_names ipcomp_transformid_names; - -/* Certificate type values - * RFC 2408 ISAKMP, chapter 3.9 - */ -enum ipsec_cert_type { - CERT_NONE= 0, - CERT_PKCS7_WRAPPED_X509= 1, - CERT_PGP= 2, - CERT_DNS_SIGNED_KEY= 3, - CERT_X509_SIGNATURE= 4, - CERT_X509_KEY_EXCHANGE= 5, - CERT_KERBEROS_TOKENS= 6, - CERT_CRL= 7, - CERT_ARL= 8, - CERT_SPKI= 9, - CERT_X509_ATTRIBUTE= 10, - CERT_RAW_RSA_KEY= 11 -}; - -/* RFC 2560 OCSP - certificate status */ - -typedef enum { - CERT_GOOD = 0, - CERT_REVOKED = 1, - CERT_UNKNOWN = 2, - CERT_UNDEFINED = 3 -} cert_status_t; - -/* RFC 3706 Dead Peer Detection */ - -extern enum_name_t *dpd_action_names; - -typedef enum { - DPD_ACTION_NONE = 0, - DPD_ACTION_CLEAR = 1, - DPD_ACTION_HOLD = 2, - DPD_ACTION_RESTART = 3, - DPD_ACTION_UNKNOWN = 4 -} dpd_action_t; - -/* Timer events */ - -extern enum_name_t *timer_event_names; - -enum event_type { - EVENT_NULL, /* non-event */ - EVENT_REINIT_SECRET, /* Refresh cookie secret */ - EVENT_SO_DISCARD, /* discard unfinished state object */ - EVENT_RETRANSMIT, /* Retransmit packet */ - EVENT_SA_REPLACE, /* SA replacement event */ - EVENT_SA_REPLACE_IF_USED, /* SA replacement event */ - EVENT_SA_EXPIRE, /* SA expiration event */ - EVENT_NAT_T_KEEPALIVE, /* NAT Traversal Keepalive */ - EVENT_DPD, /* dead peer detection */ - EVENT_DPD_TIMEOUT, /* dead peer detection timeout */ - EVENT_LOG_DAILY /* reset certain log events/stats */ -}; - -#define EVENT_REINIT_SECRET_DELAY 3600 /* 1 hour */ -#define EVENT_RETRANSMIT_DELAY_0 10 /* 10 seconds */ - -/* Misc. stuff */ - -#define MAXIMUM_RETRANSMISSIONS 2 -#define MAXIMUM_RETRANSMISSIONS_INITIAL 20 - -#define MAX_INPUT_UDP_SIZE 65536 -#define MAX_OUTPUT_UDP_SIZE 65536 - -/* Version numbers */ - -#define ISAKMP_MAJOR_VERSION 0x1 -#define ISAKMP_MINOR_VERSION 0x0 - -extern enum_names version_names; - -/* Domain of Interpretation */ - -extern enum_names doi_names; - -#define ISAKMP_DOI_ISAKMP 0 -#define ISAKMP_DOI_IPSEC 1 - -/* IPsec DOI things */ - -#define IPSEC_DOI_SITUATION_LENGTH 4 -#define IPSEC_DOI_LDI_LENGTH 4 -#define IPSEC_DOI_SPI_SIZE 4 - -/* SPI value 0 is invalid and values 1-255 are reserved to IANA. - * ESP: RFC 2402 2.4; AH: RFC 2406 2.1 - * IPComp RFC 2393 substitutes a CPI in the place of an SPI. - * see also draft-shacham-ippcp-rfc2393bis-05.txt. - * We (FreeS/WAN) reserve 0x100 to 0xFFF for manual keying, so - * Pluto won't generate these values. - */ -#define IPSEC_DOI_SPI_MIN 0x100 -#define IPSEC_DOI_SPI_OUR_MIN 0x1000 - -/* debugging settings: a set of selections for reporting - * These would be more naturally situated in log.h, - * but they are shared with whack. - * IMPAIR_* actually change behaviour, usually badly, - * to aid in testing. Naturally, these are not included in ALL. - * - * NOTE: changes here must be done in concert with changes to DBGOPT_* - * in whack.c. A change to WHACK_MAGIC in whack.h will be required too. - */ -#ifdef DEBUG -extern const char *const debug_bit_names[]; -#endif - -#define DBG_RAW LELEM(0) /* raw packet I/O */ -#define DBG_CRYPT LELEM(1) /* encryption/decryption of messages */ -#define DBG_PARSING LELEM(2) /* show decoding of messages */ -#define DBG_EMITTING LELEM(3) /* show encoding of messages */ -#define DBG_CONTROL LELEM(4) /* control flow within Pluto */ -#define DBG_LIFECYCLE LELEM(5) /* SA lifecycle */ -#define DBG_KERNEL LELEM(6) /* messages to kernel */ -#define DBG_DNS LELEM(7) /* DNS activity */ -#define DBG_NATT LELEM(8) /* NAT-T */ -#define DBG_OPPO LELEM(9) /* opportunism */ -#define DBG_CONTROLMORE LELEM(10) /* more detailed debugging */ - -#define DBG_PRIVATE LELEM(11) /* private information: DANGER! */ - -#define IMPAIR0 12 /* first bit for IMPAIR_* */ - -#define IMPAIR_DELAY_ADNS_KEY_ANSWER LELEM(IMPAIR0+0) /* sleep before answering */ -#define IMPAIR_DELAY_ADNS_TXT_ANSWER LELEM(IMPAIR0+1) /* sleep before answering */ -#define IMPAIR_BUST_MI2 LELEM(IMPAIR0+2) /* make MI2 really large */ -#define IMPAIR_BUST_MR2 LELEM(IMPAIR0+3) /* make MI2 really large */ - -#define DBG_NONE 0 /* no options on, including impairments */ -#define DBG_ALL LRANGES(DBG_RAW, DBG_CONTROLMORE) /* all logging options on EXCEPT DBG_PRIVATE */ - -/* State of exchanges - * - * The name of the state describes the last message sent, not the - * message currently being input or output (except during retry). - * In effect, the state represents the last completed action. - * - * Messages are named [MQ][IR]n where - * - M stands for Main Mode (Phase 1); - * Q stands for Quick Mode (Phase 2) - * - I stands for Initiator; - * R stands for Responder - * - n, a digit, stands for the number of the message - * - * It would be more convenient if each state accepted a message - * and produced one. This is the case for states at the start - * or end of an exchange. To fix this, we pretend that there are - * MR0 and QR0 messages before the MI1 and QR1 messages. Similarly, - * we pretend that there are MR4 and QR2 messages. - * - * STATE_MAIN_R0 and STATE_QUICK_R0 are intermediate states (not - * retained between messages) representing the state that accepts the - * first message of an exchange has been read but not processed. - * - * state_microcode state_microcode_table in demux.c describes - * other important details. - */ - -extern enum_names state_names; -extern const char *const state_story[]; - -enum state_kind { - STATE_UNDEFINED, /* 0 -- most likely accident */ - - /* IKE states */ - - STATE_MAIN_R0, - STATE_MAIN_I1, - STATE_MAIN_R1, - STATE_MAIN_I2, - STATE_MAIN_R2, - STATE_MAIN_I3, - STATE_MAIN_R3, - STATE_MAIN_I4, - - STATE_QUICK_R0, - STATE_QUICK_I1, - STATE_QUICK_R1, - STATE_QUICK_I2, - STATE_QUICK_R2, - - STATE_INFO, - STATE_INFO_PROTECTED, - - /* XAUTH states */ - - STATE_XAUTH_I0, /* initiator state (client) */ - STATE_XAUTH_R1, /* responder state (server) */ - STATE_XAUTH_I1, - STATE_XAUTH_R2, - STATE_XAUTH_I2, - STATE_XAUTH_R3, - - /* Mode Config pull states */ - - STATE_MODE_CFG_R0, /* responder state (server) */ - STATE_MODE_CFG_I1, /* initiator state (client) */ - STATE_MODE_CFG_R1, - STATE_MODE_CFG_I2, - - /* Mode Config push states */ - - STATE_MODE_CFG_I0, /* initiator state (client) */ - STATE_MODE_CFG_R3, /* responder state (server) */ - STATE_MODE_CFG_I3, - STATE_MODE_CFG_R4, - - STATE_IKE_ROOF -}; - -#define STATE_IKE_FLOOR STATE_MAIN_R0 - -#define PHASE1_INITIATOR_STATES (LELEM(STATE_MAIN_I1) | LELEM(STATE_MAIN_I2) \ - | LELEM(STATE_MAIN_I3) | LELEM(STATE_MAIN_I4)) -#define ISAKMP_SA_ESTABLISHED_STATES ( \ - LELEM(STATE_MAIN_R3) | LELEM(STATE_MAIN_I4) \ - | LELEM(STATE_XAUTH_R1) | LELEM(STATE_XAUTH_R2) | LELEM(STATE_XAUTH_R3) \ - | LELEM(STATE_XAUTH_I1) | LELEM(STATE_XAUTH_I2) \ - | LELEM(STATE_MODE_CFG_I1) | LELEM(STATE_MODE_CFG_R1) | LELEM(STATE_MODE_CFG_I2) \ - | LELEM(STATE_MODE_CFG_R3) | LELEM(STATE_MODE_CFG_I3) | LELEM(STATE_MODE_CFG_R4)) - -#define IS_PHASE1(s) ((STATE_MAIN_R0 <= (s) && (s) <= STATE_MAIN_I4) \ - || (STATE_XAUTH_I0 <= (s) && (s) <= STATE_XAUTH_R3) \ - || (STATE_MODE_CFG_R0 <= (s) && (s) <= STATE_MODE_CFG_R4)) - -#define IS_QUICK(s) (STATE_QUICK_R0 <= (s) && (s) <= STATE_QUICK_R2) -#define IS_ISAKMP_ENCRYPTED(s) (STATE_MAIN_I2 <= (s)) - -#define IS_ISAKMP_SA_ESTABLISHED(s) ( \ - (s) == STATE_MAIN_R3 \ - || (s) == STATE_MAIN_I4 \ - || (s) == STATE_XAUTH_I2 \ - || (s) == STATE_XAUTH_R3 \ - || (s) == STATE_MODE_CFG_R1 \ - || (s) == STATE_MODE_CFG_I2 \ - || (s) == STATE_MODE_CFG_I3 \ - || (s) == STATE_MODE_CFG_R4) - -#define IS_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_I2 || (s) == STATE_QUICK_R2) -#define IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(s) ((s) == STATE_QUICK_R1) - -/* kind of struct connection - * Ordered (mostly) by concreteness. Order is exploited. - */ - -extern enum_names connection_kind_names; - -enum connection_kind { - CK_GROUP, /* policy group: instantiates to template */ - CK_TEMPLATE, /* abstract connection, with wildcard */ - CK_PERMANENT, /* normal connection */ - CK_INSTANCE, /* instance of template, created for a particular attempt */ - CK_GOING_AWAY /* instance being deleted -- don't delete again */ -}; - - -/* routing status. - * Note: routing ignores source address, but erouting does not! - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ - -extern enum_names routing_story; - -/* note that this is assumed to be ordered! */ -enum routing_t { - RT_UNROUTED, /* unrouted */ - RT_UNROUTED_HOLD, /* unrouted, but HOLD shunt installed */ - RT_ROUTED_ECLIPSED, /* RT_ROUTED_PROSPECTIVE except bare HOLD or instance has eroute */ - RT_ROUTED_PROSPECTIVE, /* routed, and prospective shunt installed */ - RT_ROUTED_HOLD, /* routed, and HOLD shunt installed */ - RT_ROUTED_FAILURE, /* routed, and failure-context shunt installed */ - RT_ROUTED_TUNNEL, /* routed, and erouted to an IPSEC SA group */ - RT_UNROUTED_KEYED /* keyed, but not routed, on purpose */ -}; - -#define routed(rs) ((rs) > RT_UNROUTED_HOLD) -#define erouted(rs) ((rs) != RT_UNROUTED) -#define shunt_erouted(rs) (erouted(rs) && (rs) != RT_ROUTED_TUNNEL) - -/* Payload types - * RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) - * section 3.1 - * - * RESERVED 14-127 - * Private USE 128-255 - */ - -extern enum_names payload_names; -extern const char *const payload_name[]; - -#define ISAKMP_NEXT_NONE 0 /* No other payload following */ -#define ISAKMP_NEXT_SA 1 /* Security Association */ -#define ISAKMP_NEXT_P 2 /* Proposal */ -#define ISAKMP_NEXT_T 3 /* Transform */ -#define ISAKMP_NEXT_KE 4 /* Key Exchange */ -#define ISAKMP_NEXT_ID 5 /* Identification */ -#define ISAKMP_NEXT_CERT 6 /* Certificate */ -#define ISAKMP_NEXT_CR 7 /* Certificate Request */ -#define ISAKMP_NEXT_HASH 8 /* Hash */ -#define ISAKMP_NEXT_SIG 9 /* Signature */ -#define ISAKMP_NEXT_NONCE 10 /* Nonce */ -#define ISAKMP_NEXT_N 11 /* Notification */ -#define ISAKMP_NEXT_D 12 /* Delete */ -#define ISAKMP_NEXT_VID 13 /* Vendor ID */ -#define ISAKMP_NEXT_ATTR 14 /* Mode config Attribute */ - -#define ISAKMP_NEXT_NATD_RFC 20 /* NAT-Traversal: NAT-D (rfc) */ -#define ISAKMP_NEXT_NATOA_RFC 21 /* NAT-Traversal: NAT-OA (rfc) */ -#define ISAKMP_NEXT_ROOF 22 /* roof on payload types */ - -#define ISAKMP_NEXT_NATD_DRAFTS 130 /* NAT-Traversal: NAT-D (drafts) */ -#define ISAKMP_NEXT_NATOA_DRAFTS 131 /* NAT-Traversal: NAT-OA (drafts) */ - -/* These values are to be used within the Type field of an Attribute (14) - * ISAKMP payload. - */ -#define ISAKMP_CFG_REQUEST 1 -#define ISAKMP_CFG_REPLY 2 -#define ISAKMP_CFG_SET 3 -#define ISAKMP_CFG_ACK 4 - -extern enum_names attr_msg_type_names; - -extern enum_names modecfg_attr_names; - -/* XAUTH authentication types */ -#define XAUTH_TYPE_GENERIC 0 -#define XAUTH_TYPE_CHAP 1 -#define XAUTH_TYPE_OTP 2 -#define XAUTH_TYPE_SKEY 3 - -/* Values for XAUTH_STATUS */ -#define XAUTH_STATUS_FAIL 0 -#define XAUTH_STATUS_OK 1 - -extern enum_names xauth_type_names; - -/* Exchange types - * RFC2408 "Internet Security Association and Key Management Protocol (ISAKMP)" - * section 3.1 - * - * ISAKMP Future Use 6 - 31 - * DOI Specific Use 32 - 239 - * Private Use 240 - 255 - * - * Note: draft-ietf-ipsec-dhless-enc-mode-00.txt Appendix A - * defines "DHless RSA Encryption" as 6. - */ - -extern enum_names exchange_names; - -#define ISAKMP_XCHG_NONE 0 -#define ISAKMP_XCHG_BASE 1 -#define ISAKMP_XCHG_IDPROT 2 /* ID Protection */ -#define ISAKMP_XCHG_AO 3 /* Authentication Only */ -#define ISAKMP_XCHG_AGGR 4 /* Aggressive */ -#define ISAKMP_XCHG_INFO 5 /* Informational */ -#define ISAKMP_XCHG_MODE_CFG 6 /* Mode Config */ - -/* Extra exchange types, defined by Oakley - * RFC2409 "The Internet Key Exchange (IKE)", near end of Appendix A - */ -#define ISAKMP_XCHG_QUICK 32 /* Oakley Quick Mode */ -#define ISAKMP_XCHG_NGRP 33 /* Oakley New Group Mode */ -/* added in draft-ietf-ipsec-ike-01.txt, near end of Appendix A */ -#define ISAKMP_XCHG_ACK_INFO 34 /* Oakley Acknowledged Informational */ - -/* Flag bits */ - -extern const char *const flag_bit_names[]; - -#define ISAKMP_FLAG_ENCRYPTION 0x1 -#define ISAKMP_FLAG_COMMIT 0x2 - -/* Situation definition for IPsec DOI */ - -extern const char *const sit_bit_names[]; - -#define SIT_IDENTITY_ONLY 0x01 -#define SIT_SECRECY 0x02 -#define SIT_INTEGRITY 0x04 - -/* Protocol IDs - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.4.1 - */ - -extern enum_names protocol_names; - -#define PROTO_ISAKMP 1 -#define PROTO_IPSEC_AH 2 -#define PROTO_IPSEC_ESP 3 -#define PROTO_IPCOMP 4 - -/* warning: trans_show uses enum_show, so same static buffer is used */ -#define trans_show(p, t) \ - ((p)==PROTO_IPSEC_AH ? enum_show(&ah_transformid_names, (t)) \ - : (p)==PROTO_IPSEC_ESP ? enum_show(&esp_transformid_names, (t)) \ - : (p)==PROTO_IPCOMP ? enum_show(&ipcomp_transformid_names, (t)) \ - : "??") - -#define KEY_IKE 1 - -extern enum_names isakmp_transformid_names; - -/* the following are from RFC 2393/draft-shacham-ippcp-rfc2393bis-05.txt 3.3 */ -typedef u_int16_t cpi_t; -#define IPCOMP_CPI_SIZE 2 -#define IPCOMP_FIRST_NEGOTIATED 256 -#define IPCOMP_LAST_NEGOTIATED 61439 - -/* Identification type values - * RFC 2407 The Internet IP security Domain of Interpretation for ISAKMP 4.6.2.1 - */ - -extern enum_names ident_names; -extern enum_names cert_type_names; - -extern enum_name_t *cert_policy_names; - -typedef enum certpolicy { - CERT_ALWAYS_SEND = 0, - CERT_SEND_IF_ASKED = 1, - CERT_NEVER_SEND = 2, - - CERT_YES_SEND = 3, /* synonym for CERT_ALWAYS_SEND */ - CERT_NO_SEND = 4 /* synonym for CERT_NEVER_SEND */ -} certpolicy_t; - -/* Policies for establishing an SA - * - * These are used to specify attributes (eg. encryption) and techniques - * (eg PFS) for an SA. - * Note: certain CD_ definitions in whack.c parallel these -- keep them - * in sync! - */ - -extern const char *const sa_policy_bit_names[]; -extern const char *prettypolicy(lset_t policy); - -/* ISAKMP auth techniques (none means never negotiate) */ -#define POLICY_PSK LELEM(0) -#define POLICY_PUBKEY LELEM(1) - -#define POLICY_ISAKMP_SHIFT 0 /* log2(POLICY_PSK) */ -#define POLICY_ID_AUTH_MASK (POLICY_PSK | POLICY_PUBKEY | POLICY_XAUTH_PSK | POLICY_XAUTH_RSASIG) -#define POLICY_ISAKMP_MASK POLICY_ID_AUTH_MASK /* all so far */ - -/* Quick Mode (IPSEC) attributes */ -#define POLICY_ENCRYPT LELEM(2) /* must be first of IPSEC policies */ -#define POLICY_AUTHENTICATE LELEM(3) /* must be second */ -#define POLICY_COMPRESS LELEM(4) /* must be third */ -#define POLICY_TUNNEL LELEM(5) -#define POLICY_PFS LELEM(6) -#define POLICY_DISABLEARRIVALCHECK LELEM(7) /* suppress tunnel egress address checking */ - -#define POLICY_IPSEC_SHIFT 2 /* log2(POLICY_ENCRYPT) */ -#define POLICY_IPSEC_MASK LRANGES(POLICY_ENCRYPT, POLICY_DISABLEARRIVALCHECK) - -/* shunt attributes: what to do when routed without tunnel (2 bits) */ -#define POLICY_SHUNT_SHIFT 8 /* log2(POLICY_SHUNT_PASS) */ -#define POLICY_SHUNT_MASK (03ul << POLICY_SHUNT_SHIFT) - -#define POLICY_SHUNT_TRAP (0ul << POLICY_SHUNT_SHIFT) /* default: negotiate */ -#define POLICY_SHUNT_PASS (1ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_DROP (2ul << POLICY_SHUNT_SHIFT) -#define POLICY_SHUNT_REJECT (3ul << POLICY_SHUNT_SHIFT) - -/* fail attributes: what to do with failed negotiation (2 bits) */ - -#define POLICY_FAIL_SHIFT 10 /* log2(POLICY_FAIL_PASS) */ -#define POLICY_FAIL_MASK (03ul << POLICY_FAIL_SHIFT) - -#define POLICY_FAIL_NONE (0ul << POLICY_FAIL_SHIFT) /* default */ -#define POLICY_FAIL_PASS (1ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_DROP (2ul << POLICY_FAIL_SHIFT) -#define POLICY_FAIL_REJECT (3ul << POLICY_FAIL_SHIFT) - -/* connection policy - * Other policies could vary per state object. These live in connection. - */ -#define POLICY_DONT_REKEY LELEM(12) /* don't rekey state either Phase */ -#define POLICY_OPPO LELEM(13) /* is this opportunistic? */ -#define POLICY_GROUP LELEM(14) /* is this a group template? */ -#define POLICY_GROUTED LELEM(15) /* do we want this group routed? */ -#define POLICY_UP LELEM(16) /* do we want this up? */ -#define POLICY_MODECFG_PUSH LELEM(17) /* is modecfg pushed by server? */ -#define POLICY_XAUTH_PSK LELEM(18) /* do we support XAUTH????PreShared? */ -#define POLICY_XAUTH_RSASIG LELEM(19) /* do we support XAUTH????RSA? */ -#define POLICY_XAUTH_SERVER LELEM(20) /* are we an XAUTH server? */ -#define POLICY_DONT_REAUTH LELEM(21) /* don't reauthenticate on rekeying, IKEv2 only */ -#define POLICY_BEET LELEM(22) /* bound end2end tunnel, IKEv2 */ -#define POLICY_MOBIKE LELEM(23) /* enable MOBIKE for IKEv2 */ -#define POLICY_FORCE_ENCAP LELEM(24) /* force UDP encapsulation (IKEv2) */ -#define POLICY_PROXY LELEM(25) /* proxy transport mode (MIPv6) */ - -/* Any IPsec policy? If not, a connection description - * is only for ISAKMP SA, not IPSEC SA. (A pun, I admit.) - * Note: a connection can only be routed if it is NEVER_NEGOTIATE - * or HAS_IPSEC_POLICY. - */ -#define HAS_IPSEC_POLICY(p) (((p) & POLICY_IPSEC_MASK) != 0) - -/* Don't allow negotiation? */ -#define NEVER_NEGOTIATE(p) (LDISJOINT((p), POLICY_ID_AUTH_MASK)) - - -/* Oakley transform attributes - * draft-ietf-ipsec-ike-01.txt appendix A - */ - -extern enum_names oakley_attr_names; -extern const char *const oakley_attr_bit_names[]; - -#define OAKLEY_ENCRYPTION_ALGORITHM 1 -#define OAKLEY_HASH_ALGORITHM 2 -#define OAKLEY_AUTHENTICATION_METHOD 3 -#define OAKLEY_GROUP_DESCRIPTION 4 -#define OAKLEY_GROUP_TYPE 5 -#define OAKLEY_GROUP_PRIME 6 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_ONE 7 /* B/V */ -#define OAKLEY_GROUP_GENERATOR_TWO 8 /* B/V */ -#define OAKLEY_GROUP_CURVE_A 9 /* B/V */ -#define OAKLEY_GROUP_CURVE_B 10 /* B/V */ -#define OAKLEY_LIFE_TYPE 11 -#define OAKLEY_LIFE_DURATION 12 /* B/V */ -#define OAKLEY_PRF 13 -#define OAKLEY_KEY_LENGTH 14 -#define OAKLEY_FIELD_SIZE 15 -#define OAKLEY_GROUP_ORDER 16 /* B/V */ -#define OAKLEY_BLOCK_SIZE 17 - -/* for each Oakley attribute, which enum_names describes its values? */ -extern enum_names *oakley_attr_val_descs[]; - -/* IPsec DOI attributes - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - */ - -extern enum_names ipsec_attr_names; - -#define SA_LIFE_TYPE 1 -#define SA_LIFE_DURATION 2 /* B/V */ -#define GROUP_DESCRIPTION 3 -#define ENCAPSULATION_MODE 4 -#define AUTH_ALGORITHM 5 -#define KEY_LENGTH 6 -#define KEY_ROUNDS 7 -#define COMPRESS_DICT_SIZE 8 -#define COMPRESS_PRIVATE_ALG 9 /* B/V */ - -/* for each IPsec attribute, which enum_names describes its values? */ -extern enum_names *ipsec_attr_val_descs[]; - -/* SA Lifetime Type attribute - * RFC2407 The Internet IP security Domain of Interpretation for ISAKMP 4.5 - * Default time specified in 4.5 - * - * There are two defaults for IPSEC SA lifetime, SA_LIFE_DURATION_DEFAULT, - * and PLUTO_SA_LIFE_DURATION_DEFAULT. - * SA_LIFE_DURATION_DEFAULT is specified in RFC2407 "The Internet IP - * Security Domain of Interpretation for ISAKMP" 4.5. It applies when - * an ISAKMP negotiation does not explicitly specify a life duration. - * PLUTO_SA_LIFE_DURATION_DEFAULT is specified in pluto(8). It applies - * when a connection description does not specify --ipseclifetime. - * The value of SA_LIFE_DURATION_MAXIMUM is our local policy. - */ - -extern enum_names sa_lifetime_names; - -#define SA_LIFE_TYPE_SECONDS 1 -#define SA_LIFE_TYPE_KBYTES 2 - -#define SA_LIFE_DURATION_DEFAULT 28800 /* eight hours (RFC2407 4.5) */ -#define PLUTO_SA_LIFE_DURATION_DEFAULT 3600 /* one hour (pluto(8)) */ -#define SA_LIFE_DURATION_MAXIMUM 86400 /* one day */ - -#define SA_REPLACEMENT_MARGIN_DEFAULT 540 /* (IPSEC & IKE) nine minutes */ -#define SA_REPLACEMENT_FUZZ_DEFAULT 100 /* (IPSEC & IKE) 100% of MARGIN */ -#define SA_REPLACEMENT_RETRIES_DEFAULT 3 /* (IPSEC & IKE) */ - -#define SA_LIFE_DURATION_K_DEFAULT 0xFFFFFFFFlu - -/* Encapsulation Mode attribute */ - -extern enum_names enc_mode_names; - -#define ENCAPSULATION_MODE_UNSPECIFIED 0 /* not legal -- used internally */ -#define ENCAPSULATION_MODE_TUNNEL 1 -#define ENCAPSULATION_MODE_TRANSPORT 2 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_RFC 3 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_RFC 4 - -#define ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS 61443 -#define ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS 61444 - -/* Auth Algorithm attribute */ - -extern enum_names auth_alg_names, extended_auth_alg_names; - -#define AUTH_ALGORITHM_NONE 0 /* our private designation */ -#define AUTH_ALGORITHM_HMAC_MD5 1 -#define AUTH_ALGORITHM_HMAC_SHA1 2 -#define AUTH_ALGORITHM_DES_MAC 3 -#define AUTH_ALGORITHM_KPDK 4 -#define AUTH_ALGORITHM_HMAC_SHA2_256 5 -#define AUTH_ALGORITHM_HMAC_SHA2_384 6 -#define AUTH_ALGORITHM_HMAC_SHA2_512 7 -#define AUTH_ALGORITHM_HMAC_RIPEMD 8 -#define AUTH_ALGORITHM_AES_XCBC_MAC 9 -#define AUTH_ALGORITHM_SIG_RSA 10 -#define AUTH_ALGORITHM_AES_128_GMAC 11 -#define AUTH_ALGORITHM_AES_192_GMAC 12 -#define AUTH_ALGORITHM_AES_256_GMAC 13 -#define AUTH_ALGORITHM_NULL 251 -#define AUTH_ALGORITHM_HMAC_SHA2_256_96 252 - -/* Oakley Lifetime Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * As far as I can see, there is not specification for - * OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT. This could lead to interop problems! - * For no particular reason, we chose three hours. - * The value of OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM is our local policy. - */ -extern enum_names oakley_lifetime_names; - -#define OAKLEY_LIFE_SECONDS 1 -#define OAKLEY_LIFE_KILOBYTES 2 - -#define OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT 10800 /* three hours */ -#define OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM 86400 /* one day */ - -/* Oakley PRF attribute (none defined) - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_prf_names; - -/* HMAC (see rfc2104.txt) */ - -#define HMAC_IPAD 0x36 -#define HMAC_OPAD 0x5C - -/* Oakley Encryption Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_enc_names; - -#define OAKLEY_DES_CBC 1 -#define OAKLEY_IDEA_CBC 2 -#define OAKLEY_BLOWFISH_CBC 3 -#define OAKLEY_RC5_R16_B64_CBC 4 -#define OAKLEY_3DES_CBC 5 -#define OAKLEY_CAST_CBC 6 -#define OAKLEY_AES_CBC 7 -#define OAKLEY_CAMELLIA_CBC 8 - -#define OAKLEY_MARS_CBC 65001 -#define OAKLEY_RC6_CBC 65002 -#define OAKLEY_ID_65003 65003 -#define OAKLEY_SERPENT_CBC 65004 -#define OAKLEY_TWOFISH_CBC 65005 - -#define OAKLEY_TWOFISH_CBC_SSH 65289 - -#define OAKLEY_ENCRYPT_MAX 65535 /* pretty useless :) */ - -/* Oakley Hash Algorithm attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * and from http://www.isi.edu/in-notes/iana/assignments/ipsec-registry - */ - -extern enum_names oakley_hash_names; - -#define OAKLEY_MD5 1 -#define OAKLEY_SHA 2 -#define OAKLEY_TIGER 3 -#define OAKLEY_SHA2_256 4 -#define OAKLEY_SHA2_384 5 -#define OAKLEY_SHA2_512 6 - -#define OAKLEY_HASH_MAX 7 - -/* Oakley Authentication Method attribute - * draft-ietf-ipsec-ike-01.txt appendix A - * Goofy Hybrid extensions from draft-ietf-ipsec-isakmp-hybrid-auth-05.txt - * Goofy XAUTH extensions from draft-ietf-ipsec-isakmp-xauth-06.txt - */ - -extern enum_names oakley_auth_names; - -#define OAKLEY_PRESHARED_KEY 1 -#define OAKLEY_DSS_SIG 2 -#define OAKLEY_RSA_SIG 3 -#define OAKLEY_RSA_ENC 4 -#define OAKLEY_RSA_ENC_REV 5 -#define OAKLEY_ELGAMAL_ENC 6 -#define OAKLEY_ELGAMAL_ENC_REV 7 -#define OAKLEY_ECDSA_SIG 8 -#define OAKLEY_ECDSA_256 9 -#define OAKLEY_ECDSA_384 10 -#define OAKLEY_ECDSA_521 11 - -#define OAKLEY_AUTH_ROOF 12 /* roof on auth values THAT WE SUPPORT */ - -#define HybridInitRSA 64221 -#define HybridRespRSA 64222 -#define HybridInitDSS 64223 -#define HybridRespDSS 64224 - -#define XAUTHInitPreShared 65001 -#define XAUTHRespPreShared 65002 -#define XAUTHInitDSS 65003 -#define XAUTHRespDSS 65004 -#define XAUTHInitRSA 65005 -#define XAUTHRespRSA 65006 -#define XAUTHInitRSAEncryption 65007 -#define XAUTHRespRSAEncryption 65008 -#define XAUTHInitRSARevisedEncryption 65009 -#define XAUTHRespRSARevisedEncryption 65010 - -/* Oakley Group Description attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_names; - -/* you must also touch: constants.c, crypto.c */ - -/* Oakley Group Type attribute - * draft-ietf-ipsec-ike-01.txt appendix A - */ -extern enum_names oakley_group_type_names; - -#define OAKLEY_GROUP_TYPE_MODP 1 -#define OAKLEY_GROUP_TYPE_ECP 2 -#define OAKLEY_GROUP_TYPE_EC2N 3 - - -/* Notify messages -- error types - * See RFC2408 ISAKMP 3.14.1 - */ - -extern enum_names notification_names; -extern enum_names ipsec_notification_names; - -typedef enum { - ISAKMP_NOTHING_WRONG = 0, /* unofficial! */ - - ISAKMP_INVALID_PAYLOAD_TYPE = 1, - ISAKMP_DOI_NOT_SUPPORTED = 2, - ISAKMP_SITUATION_NOT_SUPPORTED = 3, - ISAKMP_INVALID_COOKIE = 4, - ISAKMP_INVALID_MAJOR_VERSION = 5, - ISAKMP_INVALID_MINOR_VERSION = 6, - ISAKMP_INVALID_EXCHANGE_TYPE = 7, - ISAKMP_INVALID_FLAGS = 8, - ISAKMP_INVALID_MESSAGE_ID = 9, - ISAKMP_INVALID_PROTOCOL_ID = 10, - ISAKMP_INVALID_SPI = 11, - ISAKMP_INVALID_TRANSFORM_ID = 12, - ISAKMP_ATTRIBUTES_NOT_SUPPORTED = 13, - ISAKMP_NO_PROPOSAL_CHOSEN = 14, - ISAKMP_BAD_PROPOSAL_SYNTAX = 15, - ISAKMP_PAYLOAD_MALFORMED = 16, - ISAKMP_INVALID_KEY_INFORMATION = 17, - ISAKMP_INVALID_ID_INFORMATION = 18, - ISAKMP_INVALID_CERT_ENCODING = 19, - ISAKMP_INVALID_CERTIFICATE = 20, - ISAKMP_CERT_TYPE_UNSUPPORTED = 21, - ISAKMP_INVALID_CERT_AUTHORITY = 22, - ISAKMP_INVALID_HASH_INFORMATION = 23, - ISAKMP_AUTHENTICATION_FAILED = 24, - ISAKMP_INVALID_SIGNATURE = 25, - ISAKMP_ADDRESS_NOTIFICATION = 26, - ISAKMP_NOTIFY_SA_LIFETIME = 27, - ISAKMP_CERTIFICATE_UNAVAILABLE = 28, - ISAKMP_UNSUPPORTED_EXCHANGE_TYPE = 29, - ISAKMP_UNEQUAL_PAYLOAD_LENGTHS = 30, - - /* ISAKMP status type */ - ISAKMP_CONNECTED = 16384, - - /* IPSEC DOI additions; status types (RFC2407 IPSEC DOI 4.6.3) - * These must be sent under the protection of an ISAKMP SA. - */ - IPSEC_RESPONDER_LIFETIME = 24576, - IPSEC_REPLAY_STATUS = 24577, - IPSEC_INITIAL_CONTACT = 24578, - - /* RFC 3706 DPD */ - R_U_THERE = 36136, - R_U_THERE_ACK = 36137, - - /* Juniper SRX private use */ - NS_NHTB_INFORM = 40001 - - } notification_t; - - -/* Public key algorithm number - * Same numbering as used in DNSsec - * See RFC 2535 DNSsec 3.2 The KEY Algorithm Number Specification. - * Also found in BIND 8.2.2 include/isc/dst.h as DST algorithm codes. - */ - -enum pubkey_alg -{ - PUBKEY_ALG_RSA = 1, - PUBKEY_ALG_DSA = 3, -}; - -/* Limits on size of RSA moduli. - * The upper bound matches that of DNSsec (see RFC 2537). - * The lower bound must be more than 11 octets for certain - * the encoding to work, but it must be much larger for any - * real security. For now, we require 512 bits. - */ - -#define RSA_MIN_OCTETS_RFC 12 - -#define RSA_MIN_OCTETS (512 / BITS_PER_BYTE) -#define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits" - -#define RSA_MAX_OCTETS (8192 / BITS_PER_BYTE) -#define RSA_MAX_OCTETS_UGH "RSA modulus too large: more than 8192 bits" - -/* Note: RFC 2537 encoding adds a few bytes. If you use a small - * modulus like 3, the overhead is only 2 bytes - */ -#define RSA_MAX_ENCODING_BYTES (RSA_MAX_OCTETS + 2) - -/* socket address family info */ - -struct af_info -{ - int af; - const char *name; - size_t ia_sz; - size_t sa_sz; - int mask_cnt; - u_int8_t id_addr, id_subnet, id_range; - const ip_address *any; - const ip_subnet *none; /* 0.0.0.0/32 or IPv6 equivalent */ - const ip_subnet *all; /* 0.0.0.0/0 or IPv6 equivalent */ -}; - -extern const struct af_info - af_inet4_info, - af_inet6_info; - -extern const struct af_info *aftoinfo(int af); - -extern enum_names af_names; - -#define subnetisaddr(sn, a) (subnetishost(sn) && addrinsubnet((a), (sn))) -extern bool subnetisnone(const ip_subnet *sn); - -/* BIND enumerated types */ - -extern enum_names - rr_qtype_names, - rr_type_names, - rr_class_names; - -/* How authenticated is info that might have come from DNS? - * In order of increasing confidence. - */ -enum dns_auth_level { - DAL_UNSIGNED, /* AD in response, but no signature: no authentication */ - DAL_NOTSEC, /* no AD in response: authentication impossible */ - DAL_SIGNED, /* AD and signature in response: authentic */ - DAL_LOCAL /* locally provided (pretty good) */ -}; - -/* - * define a macro for use in error messages - */ - -#ifdef USE_KEYRR -#define RRNAME "TXT or KEY" -#else -#define RRNAME "TXT" -#endif - -/* natt traversal types */ -extern const char *const natt_type_bitnames[]; - -/* secret value for responder cookies */ -extern u_char secret_of_the_day[HASH_SIZE_SHA1]; - -#endif /* _CONSTANTS_H */ diff --git a/src/pluto/cookie.c b/src/pluto/cookie.c deleted file mode 100644 index 00c863f18..000000000 --- a/src/pluto/cookie.c +++ /dev/null @@ -1,73 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "cookie.h" - -const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -/* Generate a cookie. - * First argument is true if we're to create an Initiator cookie. - * Length SHOULD be a multiple of sizeof(u_int32_t). - */ -void get_cookie(bool initiator, u_int8_t *cookie, int length, ip_address *addr) -{ - hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - u_char buffer[HASH_SIZE_SHA1]; - - do { - if (initiator) - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, length, cookie); - rng->destroy(rng); - } - else /* Responder cookie */ - { - chunk_t addr_chunk, secret_chunk, counter_chunk; - size_t addr_len; - static u_int32_t counter = 0; - unsigned char addr_buf[ - sizeof(union {struct in_addr A; struct in6_addr B;})]; - - addr_len = addrbytesof(addr, addr_buf, sizeof(addr_buf)); - addr_chunk = chunk_create(addr_buf, addr_len); - secret_chunk = chunk_create(secret_of_the_day, HASH_SIZE_SHA1); - counter++; - counter_chunk = chunk_create((void *) &counter, sizeof(counter)); - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, secret_chunk, NULL); - hasher->get_hash(hasher, counter_chunk, buffer); - memcpy(cookie, buffer, length); - } - } while (is_zero_cookie(cookie)); /* probably never loops */ - - hasher->destroy(hasher); -} diff --git a/src/pluto/cookie.h b/src/pluto/cookie.h deleted file mode 100644 index 809d66491..000000000 --- a/src/pluto/cookie.h +++ /dev/null @@ -1,22 +0,0 @@ -/* cookie generation/verification routines. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */ - -extern void get_cookie(bool initiator, u_int8_t *cookie, int length, - ip_address *addr); - -#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE) diff --git a/src/pluto/crl.c b/src/pluto/crl.c deleted file mode 100644 index c49b09e19..000000000 --- a/src/pluto/crl.c +++ /dev/null @@ -1,541 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "keys.h" -#include "whack.h" -#include "fetch.h" -#include "builder.h" - - -/* chained lists of X.509 crls */ - -static x509crl_t *x509crls = NULL; - -/** - * Get the X.509 CRL with a given issuer - */ -static x509crl_t* get_x509crl(identification_t *issuer, chunk_t keyid) -{ - x509crl_t *x509crl = x509crls; - x509crl_t *prev_crl = NULL; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *crl_issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) : - issuer->equals(issuer, crl_issuer)) - { - if (x509crl != x509crls) - { - /* bring the CRL up front */ - prev_crl->next = x509crl->next; - x509crl->next = x509crls; - x509crls = x509crl; - } - return x509crl; - } - prev_crl = x509crl; - x509crl = x509crl->next; - } - return NULL; -} - -/** - * Free the dynamic memory used to store CRLs - */ -void free_crl(x509crl_t *crl) -{ - DESTROY_IF(crl->crl); - crl->distributionPoints->destroy_function(crl->distributionPoints, free); - free(crl); -} - -static void free_first_crl(void) -{ - x509crl_t *crl = x509crls; - - x509crls = crl->next; - free_crl(crl); -} - -void free_crls(void) -{ - lock_crl_list("free_crls"); - - while (x509crls != NULL) - { - free_first_crl(); - } - - unlock_crl_list("free_crls"); -} - -/** - * Insert X.509 CRL into chained list - */ -bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl) -{ - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - x509crl_t *oldcrl; - time_t now, nextUpdate; - bool valid_sig; - - /* add distribution point */ - add_distribution_point(x509crl->distributionPoints, crl_uri); - - lock_authcert_list("insert_crl"); - - /* get the issuer cacert */ - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - if (issuer_cert == NULL) - { - plog("crl issuer cacert not found"); - free_crl(x509crl); - unlock_authcert_list("insert_crl"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl issuer cacert found") - ) - - /* check the issuer's signature of the crl */ - valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert); - unlock_authcert_list("insert_crl"); - - if (!valid_sig) - { - free_crl(x509crl); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* note the current time */ - time(&now); - - lock_crl_list("insert_crl"); - oldcrl = get_x509crl(issuer, authKeyID); - - if (oldcrl != NULL) - { - certificate_t *old_cert_crl = oldcrl->crl; - - if (crl_is_newer((crl_t*)cert_crl, (crl_t*)old_cert_crl)) - { - /* keep any known CRL distribution points */ - add_distribution_points(x509crl->distributionPoints, - oldcrl->distributionPoints); - - /* now delete the old CRL */ - free_first_crl(); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is newer - existing crl deleted") - ) - } - else - { - unlock_crl_list("insert_crls"); - DBG(DBG_CONTROL, - DBG_log("thisUpdate is not newer - existing crl not replaced"); - ) - free_crl(x509crl); - old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; - } - } - - /* insert new CRL */ - x509crl->next = x509crls; - x509crls = x509crl; - - unlock_crl_list("insert_crl"); - - /* If crl caching is enabled then the crl is saved locally. - * Only http or ldap URIs are cached but not local file URIs. - * The CRL's authorityKeyIdentifier is used as a unique filename - */ - if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) - { - char buf[BUF_LEN]; - chunk_t hex, encoding; - - hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE); - snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex.ptr); - free(hex.ptr); - - if (cert_crl->get_encoding(cert_crl, CERT_ASN1_DER, &encoding)) - { - chunk_write(encoding, buf, "crl", 022, TRUE); - free(encoding.ptr); - } - } - - /* is the fetched crl valid? */ - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - return nextUpdate - now > 2*crl_check_interval; -} - -/** - * Loads CRLs - */ -void load_crls(void) -{ - struct dirent **filelist; - u_char buf[BUF_LEN]; - u_char *save_dir; - int n; - - /* change directory to specified path */ - save_dir = getcwd(buf, BUF_LEN); - if (chdir(CRL_PATH)) - { - plog("Could not change to directory '%s'", CRL_PATH); - } - else - { - plog("Changing to directory '%s'", CRL_PATH); - n = scandir(CRL_PATH, &filelist, file_select, alphasort); - - if (n < 0) - plog(" scandir() error"); - else - { - while (n--) - { - char *filename = filelist[n]->d_name; - x509crl_t *x509crl; - - x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, - CERT_PLUTO_CRL, - BUILD_FROM_FILE, filename, BUILD_END); - if (x509crl) - { - char crl_uri[BUF_LEN]; - - plog(" loaded crl from '%s'", filename); - snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); - insert_crl(x509crl, crl_uri, FALSE); - } - free(filelist[n]); - } - free(filelist); - } - } - /* restore directory path */ - ignore_result(chdir(save_dir)); -} - - -/* Checks if the current certificate is revoked. It goes through the - * list of revoked certificates of the corresponding crl. Either the - * status CERT_GOOD or CERT_REVOKED is returned - */ -static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - enumerator_t *enumerator; - cert_status_t status; - chunk_t serial; - - DBG(DBG_CONTROL, - DBG_log("serial number: %#B", &cert_serial) - ) - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - status = CERT_GOOD; - - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, &serial, - revocationDate, revocationReason)) - { - if (chunk_equals(serial, cert_serial)) - { - status = CERT_REVOKED; - break; - } - } - enumerator->destroy(enumerator); - return status; -} - -/* - * check if any crls are about to expire - */ -void check_crls(void) -{ - x509crl_t *x509crl; - time_t now, nextUpdate, time_left; - - lock_crl_list("check_crls"); - time(&now); - x509crl = x509crls; - - while (x509crl != NULL) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - identification_t *issuer = cert_crl->get_issuer(cert_crl); - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - - cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate); - time_left = nextUpdate - now; - - DBG(DBG_CONTROL, - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - DBG_log("%ld seconds left", time_left) - ) - if (time_left < 2*crl_check_interval) - { - fetch_req_t *req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - add_crl_fetch_request(req); - } - x509crl = x509crl->next; - } - unlock_crl_list("check_crls"); -} - -/* - * verify if a cert hasn't been revoked by a crl - */ -cert_status_t verify_by_crl(cert_t *cert, time_t *until, time_t *revocationDate, - crl_reason_t *revocationReason) -{ - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - x509crl_t *x509crl; - ca_info_t *ca; - enumerator_t *enumerator; - x509_cdp_t *cdp; - - ca = get_ca_info(issuer, authKeyID); - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - lock_crl_list("verify_by_crl"); - x509crl = get_x509crl(issuer, authKeyID); - - if (x509crl == NULL) - { - linked_list_t *crluris; - - unlock_crl_list("verify_by_crl"); - plog("crl not found"); - - crluris = linked_list_create(); - if (ca) - { - add_distribution_points(crluris, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(crluris, cdp->uri); - } - enumerator->destroy(enumerator); - - if (crluris->get_count(crluris) > 0) - { - fetch_req_t *req; - - req = build_crl_fetch_request(issuer, authKeyID, crluris); - crluris->destroy_function(crluris, free); - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - return CERT_UNKNOWN; - } - else - { - crluris->destroy(crluris); - return CERT_UNDEFINED; - } - } - else - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t authKeyID = crl->get_authKeyIdentifier(crl); - cert_t *issuer_cert; - bool trusted, valid; - - DBG(DBG_CONTROL, - DBG_log("crl found") - ) - - if (ca) - { - add_distribution_points(x509crl->distributionPoints, ca->crluris); - } - - enumerator = x509->create_crl_uri_enumerator(x509); - while (enumerator->enumerate(enumerator, &cdp)) - { - add_distribution_point(x509crl->distributionPoints, cdp->uri); - } - enumerator->destroy(enumerator); - - lock_authcert_list("verify_by_crl"); - - issuer_cert = get_authcert(issuer, authKeyID, X509_CA); - trusted = issuer_cert ? cert_crl->issued_by(cert_crl, issuer_cert->cert) - : FALSE; - - unlock_authcert_list("verify_by_crl"); - - if (trusted) - { - cert_status_t status; - - DBG(DBG_CONTROL, - DBG_log("crl signature is valid") - ) - - /* return the expiration date */ - valid = cert_crl->get_validity(cert_crl, NULL, NULL, until); - - /* has the certificate been revoked? */ - status = check_revocation(crl, x509->get_serial(x509), revocationDate - , revocationReason); - - if (valid) - { - unlock_crl_list("verify_by_crl"); - DBG(DBG_CONTROL, - DBG_log("crl is valid: until %T", until, FALSE) - ) - } - else - { - fetch_req_t *req; - - DBG(DBG_CONTROL, - DBG_log("crl is stale: since %T", until, FALSE) - ) - - /* try to fetch a crl update */ - req = build_crl_fetch_request(issuer, authKeyID, - x509crl->distributionPoints); - unlock_crl_list("verify_by_crl"); - - add_crl_fetch_request(req); - wake_fetch_thread("verify_by_crl"); - } - return status; - } - else - { - unlock_crl_list("verify_by_crl"); - plog("crl signature is invalid"); - return CERT_UNKNOWN; - } - } -} - -/* - * list all X.509 crls in the chained list - */ -void list_crls(bool utc, bool strict) -{ - x509crl_t *x509crl; - - lock_crl_list("list_crls"); - x509crl = x509crls; - - if (x509crl) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of X.509 CRLs:"); - } - - while (x509crl) - { - certificate_t *cert_crl = x509crl->crl; - crl_t *crl = (crl_t*)cert_crl; - chunk_t serial, authKeyID; - time_t thisUpdate, nextUpdate; - u_int revoked = 0; - enumerator_t *enumerator; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " issuer: \"%Y\"", - cert_crl->get_issuer(cert_crl)); - serial = chunk_skip_zero(crl->get_serial(crl)); - if (serial.ptr) - { - whack_log(RC_COMMENT, " serial: %#B", &serial); - } - - /* count number of revoked certificates in CRL */ - enumerator = crl->create_enumerator(crl); - while (enumerator->enumerate(enumerator, NULL, NULL, NULL)) - { - revoked++; - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, " revoked: %d certificates", revoked); - - list_distribution_points(x509crl->distributionPoints); - - cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate); - whack_log(RC_COMMENT, " updates: this %T", &thisUpdate, utc); - whack_log(RC_COMMENT, " next %T %s", &nextUpdate, utc, - check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict)); - authKeyID = crl->get_authKeyIdentifier(crl); - if (authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &authKeyID); - } - - x509crl = x509crl->next; - } - unlock_crl_list("list_crls"); -} - diff --git a/src/pluto/crl.h b/src/pluto/crl.h deleted file mode 100644 index 43bafe145..000000000 --- a/src/pluto/crl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of X.509 certificate revocation lists (CRLs) - * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include -#include -#include - -/* storage structure for an X.509 CRL */ - -typedef struct x509crl x509crl_t; - -struct x509crl { - certificate_t *crl; - x509crl_t *next; - linked_list_t *distributionPoints; -}; - -/* apply a strict CRL policy - * flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c - */ -extern bool strict_crl_policy; - -/* - * cache the retrieved CRLs by storing them locally as a file - */ -extern bool cache_crls; - -/* - * check periodically for expired crls - */ -extern long crl_check_interval; -extern void load_crls(void); -extern void check_crls(void); -extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); -extern cert_status_t verify_by_crl(cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason); -extern void list_crls(bool utc, bool strict); -extern void free_crls(void); -extern void free_crl(x509crl_t *crl); diff --git a/src/pluto/crypto.c b/src/pluto/crypto.c deleted file mode 100644 index a4f678222..000000000 --- a/src/pluto/crypto.c +++ /dev/null @@ -1,698 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2007-2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "log.h" - -static struct encrypt_desc encrypt_desc_3des = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_3DES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: DES_BLOCK_SIZE, - keydeflen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keyminlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, - keymaxlen: DES_BLOCK_SIZE * 3 * BITS_PER_BYTE, -}; - -#define AES_KEY_MIN_LEN 128 -#define AES_KEY_DEF_LEN 128 -#define AES_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_aes = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_AES_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: AES_BLOCK_SIZE, - keyminlen: AES_KEY_MIN_LEN, - keydeflen: AES_KEY_DEF_LEN, - keymaxlen: AES_KEY_MAX_LEN, -}; - -#define CAMELLIA_KEY_MIN_LEN 128 -#define CAMELLIA_KEY_DEF_LEN 128 -#define CAMELLIA_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_camellia = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_CAMELLIA_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: CAMELLIA_BLOCK_SIZE, - keyminlen: CAMELLIA_KEY_MIN_LEN, - keydeflen: CAMELLIA_KEY_DEF_LEN, - keymaxlen: CAMELLIA_KEY_MAX_LEN, -}; - -#define BLOWFISH_KEY_MIN_LEN 128 -#define BLOWFISH_KEY_MAX_LEN 448 - -static struct encrypt_desc encrypt_desc_blowfish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_BLOWFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: BLOWFISH_BLOCK_SIZE, - keyminlen: BLOWFISH_KEY_MIN_LEN, - keydeflen: BLOWFISH_KEY_MIN_LEN, - keymaxlen: BLOWFISH_KEY_MAX_LEN, -}; - -#define SERPENT_KEY_MIN_LEN 128 -#define SERPENT_KEY_DEF_LEN 128 -#define SERPENT_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_serpent = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_SERPENT_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: SERPENT_BLOCK_SIZE, - keyminlen: SERPENT_KEY_MIN_LEN, - keydeflen: SERPENT_KEY_DEF_LEN, - keymaxlen: SERPENT_KEY_MAX_LEN, -}; - -#define TWOFISH_KEY_MIN_LEN 128 -#define TWOFISH_KEY_DEF_LEN 128 -#define TWOFISH_KEY_MAX_LEN 256 - -static struct encrypt_desc encrypt_desc_twofish = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct encrypt_desc encrypt_desc_twofish_ssh = -{ - algo_type: IKE_ALG_ENCRYPT, - algo_id: OAKLEY_TWOFISH_CBC_SSH, - plugin_name: NULL, - algo_next: NULL, - - enc_blocksize: TWOFISH_BLOCK_SIZE, - keydeflen: TWOFISH_KEY_MIN_LEN, - keyminlen: TWOFISH_KEY_DEF_LEN, - keymaxlen: TWOFISH_KEY_MAX_LEN, -}; - -static struct hash_desc hash_desc_md5 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_MD5, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_MD5, -}; - -static struct hash_desc hash_desc_sha1 = -{ - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA1, -}; - -static struct hash_desc hash_desc_sha2_256 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_256, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA256, -}; - -static struct hash_desc hash_desc_sha2_384 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_384, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA384, -}; - -static struct hash_desc hash_desc_sha2_512 = { - algo_type: IKE_ALG_HASH, - algo_id: OAKLEY_SHA2_512, - plugin_name: NULL, - algo_next: NULL, - hash_digest_size: HASH_SIZE_SHA512, -}; - -const struct dh_desc unset_group = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_NONE, - plugin_name: NULL, - algo_next: NULL, - ke_size: 0 -}; - -static struct dh_desc dh_desc_modp_1024 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1536 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1536_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1536 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_BIT, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_3072 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_3072_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 3072 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_4096 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_4096_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 4096 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_6144 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_6144_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 6144 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_8192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_8192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 8192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_256_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*256 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_384 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_384_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*384 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_521 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_521_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*528 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_1024_160 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_1024_160, - plugin_name: NULL, - algo_next: NULL, - ke_size: 1024 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_224, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_modp_2048_256 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: MODP_2048_256, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2048 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_192 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_192_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*192 / BITS_PER_BYTE -}; - -static struct dh_desc dh_desc_ecp_224 = { - algo_type: IKE_ALG_DH_GROUP, - algo_id: ECP_224_BIT, - plugin_name: NULL, - algo_next: NULL, - ke_size: 2*224 / BITS_PER_BYTE -}; - -bool init_crypto(void) -{ - enumerator_t *enumerator; - encryption_algorithm_t encryption_alg; - hash_algorithm_t hash_alg; - diffie_hellman_group_t dh_group; - const char *plugin_name; - bool no_md5 = TRUE; - bool no_sha1 = TRUE; - - enumerator = lib->crypto->create_hasher_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &hash_alg, &plugin_name)) - { - const struct hash_desc *desc; - - switch (hash_alg) - { - case HASH_SHA1: - desc = &hash_desc_sha1; - no_sha1 = FALSE; - break; - case HASH_SHA256: - desc = &hash_desc_sha2_256; - break; - case HASH_SHA384: - desc = &hash_desc_sha2_384; - break; - case HASH_SHA512: - desc = &hash_desc_sha2_512; - break; - case HASH_MD5: - desc = &hash_desc_md5; - no_md5 = FALSE; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - if (no_sha1 || no_md5) - { - plog("pluto cannot run without a %s%s%s hasher", - (no_sha1) ? "SHA-1" : "", - (no_sha1 && no_md5) ? " and " : "", - (no_md5) ? "MD5" : ""); - return FALSE; - } - - enumerator = lib->crypto->create_crypter_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &encryption_alg, &plugin_name)) - { - const struct encrypt_desc *desc; - - switch (encryption_alg) - { - case ENCR_3DES: - desc = &encrypt_desc_3des; - break; - case ENCR_BLOWFISH: - desc = &encrypt_desc_blowfish; - break; - case ENCR_AES_CBC: - desc = &encrypt_desc_aes; - break; - case ENCR_CAMELLIA_CBC: - desc = &encrypt_desc_camellia; - break; - case ENCR_TWOFISH_CBC: - desc = &encrypt_desc_twofish; - ike_alg_add((struct ike_alg *)&encrypt_desc_twofish_ssh, - plugin_name); - break; - case ENCR_SERPENT_CBC: - desc = &encrypt_desc_serpent; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - - enumerator = lib->crypto->create_dh_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &dh_group, &plugin_name)) - { - const struct dh_desc *desc; - - switch (dh_group) - { - case MODP_1024_BIT: - desc = &dh_desc_modp_1024; - break; - case MODP_1536_BIT: - desc = &dh_desc_modp_1536; - break; - case MODP_2048_BIT: - desc = &dh_desc_modp_2048; - break; - case MODP_3072_BIT: - desc = &dh_desc_modp_3072; - break; - case MODP_4096_BIT: - desc = &dh_desc_modp_4096; - break; - case MODP_6144_BIT: - desc = &dh_desc_modp_6144; - break; - case MODP_8192_BIT: - desc = &dh_desc_modp_8192; - break; - case ECP_256_BIT: - desc = &dh_desc_ecp_256; - break; - case ECP_384_BIT: - desc = &dh_desc_ecp_384; - break; - case ECP_521_BIT: - desc = &dh_desc_ecp_521; - break; - case MODP_1024_160: - desc = &dh_desc_modp_1024_160; - break; - case MODP_2048_224: - desc = &dh_desc_modp_2048_224; - break; - case MODP_2048_256: - desc = &dh_desc_modp_2048_256; - break; - case ECP_192_BIT: - desc = &dh_desc_ecp_192; - break; - case ECP_224_BIT: - desc = &dh_desc_ecp_224; - break; - default: - continue; - } - ike_alg_add((struct ike_alg *)desc, plugin_name); - } - enumerator->destroy(enumerator); - return TRUE; -} - -void free_crypto(void) -{ - /* currently nothing to do */ -} - -/** - * Converts IKEv1 encryption algorithm name to crypter name - */ -encryption_algorithm_t oakley_to_encryption_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_DES_CBC: - return ENCR_DES; - case OAKLEY_IDEA_CBC: - return ENCR_IDEA; - case OAKLEY_BLOWFISH_CBC: - return ENCR_BLOWFISH; - case OAKLEY_RC5_R16_B64_CBC: - return ENCR_RC5; - case OAKLEY_3DES_CBC: - return ENCR_3DES; - case OAKLEY_CAST_CBC: - return ENCR_CAST; - case OAKLEY_AES_CBC: - return ENCR_AES_CBC; - case OAKLEY_CAMELLIA_CBC: - return ENCR_CAMELLIA_CBC; - case OAKLEY_SERPENT_CBC: - return ENCR_SERPENT_CBC; - case OAKLEY_TWOFISH_CBC: - case OAKLEY_TWOFISH_CBC_SSH: - return ENCR_TWOFISH_CBC; - default: - return ENCR_UNDEFINED; - } -} - -/** - * Converts IKEv1 hash algorithm name to hasher name - */ -hash_algorithm_t oakley_to_hash_algorithm(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return HASH_MD5; - case OAKLEY_SHA: - return HASH_SHA1; - case OAKLEY_SHA2_256: - return HASH_SHA256; - case OAKLEY_SHA2_384: - return HASH_SHA384; - case OAKLEY_SHA2_512: - return HASH_SHA512; - default: - return HASH_UNKNOWN; - } -} - -/** - * Converts IKEv1 hash algorithm name to IKEv2 prf name - */ -pseudo_random_function_t oakley_to_prf(int alg) -{ - switch (alg) - { - case OAKLEY_MD5: - return PRF_HMAC_MD5; - case OAKLEY_SHA: - return PRF_HMAC_SHA1; - case OAKLEY_SHA2_256: - return PRF_HMAC_SHA2_256; - case OAKLEY_SHA2_384: - return PRF_HMAC_SHA2_384; - case OAKLEY_SHA2_512: - return PRF_HMAC_SHA2_512; - default: - return PRF_UNDEFINED; - } -} - -/** - * Maps IKEv1 authentication method to IKEv2 signature scheme - */ -signature_scheme_t oakley_to_signature_scheme(int method) -{ - switch (method) - { - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - return SIGN_RSA_EMSA_PKCS1_NULL; - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - return SIGN_ECDSA_WITH_NULL; - default: - return SIGN_UNKNOWN; - } -} - -/** - * Table to map IKEv2 encryption algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - encryption_algorithm_t alg; - int oakley; - int esp; -} encr_map[] = { - {ENCR_DES, OAKLEY_DES_CBC, ESP_DES }, - {ENCR_3DES, OAKLEY_3DES_CBC, ESP_3DES }, - {ENCR_RC5, OAKLEY_RC5_R16_B64_CBC, ESP_RC5 }, - {ENCR_IDEA, OAKLEY_IDEA_CBC, ESP_IDEA }, - {ENCR_CAST, OAKLEY_CAST_CBC, ESP_CAST }, - {ENCR_BLOWFISH, OAKLEY_BLOWFISH_CBC, ESP_BLOWFISH }, - {ENCR_AES_CBC, OAKLEY_AES_CBC, ESP_AES }, - {ENCR_CAMELLIA_CBC, OAKLEY_CAMELLIA_CBC, ESP_CAMELLIA }, - {ENCR_SERPENT_CBC, OAKLEY_SERPENT_CBC, ESP_SERPENT }, - {ENCR_TWOFISH_CBC, OAKLEY_TWOFISH_CBC, ESP_TWOFISH }, - {ENCR_NULL, 0, ESP_NULL }, - {ENCR_AES_CTR, 0, ESP_AES_CTR }, - {ENCR_AES_CCM_ICV8, 0, ESP_AES_CCM_8 }, - {ENCR_AES_CCM_ICV12, 0, ESP_AES_CCM_12}, - {ENCR_AES_CCM_ICV16, 0, ESP_AES_CCM_16}, - {ENCR_AES_GCM_ICV8, 0, ESP_AES_GCM_8 }, - {ENCR_AES_GCM_ICV12, 0, ESP_AES_GCM_12}, - {ENCR_AES_GCM_ICV16, 0, ESP_AES_GCM_16}, - {ENCR_NULL_AUTH_AES_GMAC, 0, ESP_AES_GMAC }, -}; - -/** - * Converts IKEv2 encryption to IKEv1 encryption algorithm - */ -int oakley_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 encryption to IKEv1 ESP encryption algorithm - */ -int esp_from_encryption_algorithm(encryption_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].alg == alg) - { - return encr_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP encryption to IKEv2 algorithm - */ -encryption_algorithm_t encryption_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(encr_map); i++) - { - if (encr_map[i].esp == esp) - { - return encr_map[i].alg; - } - } - return 0; -} - -/** - * Table to map IKEv2 integrity algorithms to IKEv1 (or IKEv1 ESP) and back - */ -struct { - integrity_algorithm_t alg; - int oakley; - int esp; -} auth_map[] = { - {AUTH_HMAC_MD5_96, OAKLEY_MD5, AUTH_ALGORITHM_HMAC_MD5 }, - {AUTH_HMAC_SHA1_96, OAKLEY_SHA, AUTH_ALGORITHM_HMAC_SHA1 }, - {AUTH_HMAC_SHA2_256_96, 0, AUTH_ALGORITHM_HMAC_SHA2_256_96}, - {AUTH_HMAC_SHA2_256_128, OAKLEY_SHA2_256, AUTH_ALGORITHM_HMAC_SHA2_256 }, - {AUTH_HMAC_SHA2_384_192, OAKLEY_SHA2_384, AUTH_ALGORITHM_HMAC_SHA2_384 }, - {AUTH_HMAC_SHA2_512_256, OAKLEY_SHA2_512, AUTH_ALGORITHM_HMAC_SHA2_512 }, - {AUTH_AES_XCBC_96, 0, AUTH_ALGORITHM_AES_XCBC_MAC }, - {AUTH_AES_128_GMAC, 0, AUTH_ALGORITHM_AES_128_GMAC }, - {AUTH_AES_192_GMAC, 0, AUTH_ALGORITHM_AES_192_GMAC }, - {AUTH_AES_256_GMAC, 0, AUTH_ALGORITHM_AES_256_GMAC }, -}; - - -/** - * Converts IKEv2 integrity to IKEv1 hash algorithm - */ -int oakley_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].oakley; - } - } - return 0; -} - -/** - * Converts IKEv2 integrity to IKEv1 ESP authentication algorithm - */ -int esp_from_integrity_algorithm(integrity_algorithm_t alg) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].alg == alg) - { - return auth_map[i].esp; - } - } - return 0; -} - -/** - * Converts IKEv1 ESP authentication to IKEv2 integrity algorithm - */ -integrity_algorithm_t integrity_algorithm_from_esp(int esp) -{ - int i; - for (i = 0; i < countof(auth_map); i++) - { - if (auth_map[i].esp == esp) - { - return auth_map[i].alg; - } - } - return 0; -} - diff --git a/src/pluto/crypto.h b/src/pluto/crypto.h deleted file mode 100644 index 16ad12780..000000000 --- a/src/pluto/crypto.h +++ /dev/null @@ -1,64 +0,0 @@ -/* crypto interfaces - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998, 1999 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include "ike_alg.h" - -extern bool init_crypto(void); -extern void free_crypto(void); - -extern const struct dh_desc unset_group; /* magic signifier */ - -/* unification of cryptographic encoding/decoding algorithms - * The IV is taken from and returned to st->st_new_iv. - * This allows the old IV to be retained. - * Use update_iv to commit to the new IV (for example, once a packet has - * been validated). - */ - -#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE) -#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE) - -struct state; /* forward declaration, dammit */ - -#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \ - , (st)->st_iv_len = (st)->st_new_iv_len) - -#define set_ph1_iv(st, iv) \ - passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \ - memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len); - -/* unification of cryptographic hashing mechanisms */ - -extern encryption_algorithm_t oakley_to_encryption_algorithm(int alg); -extern hash_algorithm_t oakley_to_hash_algorithm(int alg); -extern pseudo_random_function_t oakley_to_prf(int alg); -extern signature_scheme_t oakley_to_signature_scheme(int method); -extern int oakley_from_encryption_algorithm(encryption_algorithm_t alg); -extern int oakley_from_integrity_algorithm(integrity_algorithm_t alg); -extern int esp_from_encryption_algorithm(encryption_algorithm_t alg); -extern int esp_from_integrity_algorithm(integrity_algorithm_t alg); -extern encryption_algorithm_t encryption_algorithm_from_esp(int esp); -extern integrity_algorithm_t integrity_algorithm_from_esp(int esp); - diff --git a/src/pluto/db_ops.c b/src/pluto/db_ops.c deleted file mode 100644 index 547ea5f22..000000000 --- a/src/pluto/db_ops.c +++ /dev/null @@ -1,412 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* - * The stratedy is to have (full contained) struct db_prop in db_context - * pointing to ONE dynamically sizable transform vector (trans0). - * Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0) - * in a "serialized" way (attributes storage is used in linear sequence for - * subsecuent transforms). - * - * Resizing for both trans0 and attrs0 is supported: - * - For trans0: quite simple, just allocate and copy trans. vector content - * also update trans_cur (by offset) - * - For attrs0: after allocating and copying attrs, I must rewrite each - * trans->attrs present in trans0; to achieve this, calculate - * attrs pointer offset (new minus old) and iterate over - * each transform "adding" this difference. - * also update attrs_cur (by offset) - * - * db_context structure: - * +---------------------+ - * | prop | - * | .protoid | - * | .trans | --+ - * | .trans_cnt | | - * +---------------------+ <-+ - * | trans0 | ----> { trans#1 | ... | trans#i | ... } - * +---------------------+ ^ - * | trans_cur | ----------------------' current transf. - * +---------------------+ - * | attrs0 | ----> { attr#1 | ... | attr#j | ... } - * +---------------------+ ^ - * | attrs_cur | ---------------------' current attr. - * +---------------------+ - * | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector - * +---------------------+ - * - * See testing examples at end for interface usage. - */ -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "db_ops.h" -#include "log.h" -#include "whack.h" - -#include - -#ifdef NOT_YET -/* - * Allocator cache: - * Because of the single-threaded nature of pluto/spdb.c, - * alloc()/free() is exercised many times with very small - * lifetime objects. - * Just caching last object (currently it will select the - * largest) will avoid this allocation mas^Wperturbations - * - */ -struct db_ops_alloc_cache { - void *ptr; - int size; -}; -#endif - -#ifndef NO_DB_OPS_STATS -/* - * stats: do account for allocations - * displayed in db_ops_show_status() - */ -struct db_ops_stats { - int st_curr_cnt; /* current number of allocations */ - int st_total_cnt; /* total allocations so far */ - size_t st_maxsz; /* max. size requested */ -}; -#define DB_OPS_ZERO { 0, 0, 0}; -#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}" -#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} " -#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz -static struct db_ops_stats db_context_st = DB_OPS_ZERO; -static struct db_ops_stats db_trans_st = DB_OPS_ZERO; -static struct db_ops_stats db_attrs_st = DB_OPS_ZERO; -static __inline__ void *malloc_bytes_st(size_t size, struct db_ops_stats *st) -{ - void *ptr = malloc(size); - if (ptr) - { - st->st_curr_cnt++; - st->st_total_cnt++; - if (size > st->st_maxsz) st->st_maxsz=size; - } - return ptr; -} -#define ALLOC_BYTES_ST(z,st) malloc_bytes_st(z, &st); -#define PFREE_ST(p,st) do { st.st_curr_cnt--; free(p); } while (0); - -#else - -#define ALLOC_BYTES_ST(z,n) malloc(z); -#define PFREE_ST(p,n) free(p); - -#endif /* NO_DB_OPS_STATS */ -/* Initialize db object - * max_trans and max_attrs can be 0, will be dynamically expanded - * as a result of "add" operations - */ -int -db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs) -{ - ctx->trans0 = NULL; - ctx->attrs0 = NULL; - - if (max_trans > 0) { /* quite silly if not */ - ctx->trans0 = ALLOC_BYTES_ST ( sizeof(struct db_trans) * max_trans, - db_trans_st); - memset(ctx->trans0, '\0', sizeof(struct db_trans) * max_trans); - } - - if (max_attrs > 0) { /* quite silly if not */ - ctx->attrs0 = ALLOC_BYTES_ST (sizeof(struct db_attr) * max_attrs, - db_attrs_st); - memset(ctx->attrs0, '\0', sizeof(struct db_attr) * max_attrs); - } - - ctx->max_trans = max_trans; - ctx->max_attrs = max_attrs; - ctx->trans_cur = ctx->trans0; - ctx->attrs_cur = ctx->attrs0; - ctx->prop.protoid = protoid; - ctx->prop.trans = ctx->trans0; - ctx->prop.trans_cnt = 0; - return 0; -} - -/* Expand storage for transforms by number delta_trans */ -static int -db_trans_expand(struct db_context *ctx, int delta_trans) -{ - int ret = -1; - struct db_trans *new_trans, *old_trans; - int max_trans = ctx->max_trans + delta_trans; - int offset; - - old_trans = ctx->trans0; - new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans, - db_trans_st); - if (!new_trans) - goto out; - memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans)); - - /* update trans0 (obviously) */ - ctx->trans0 = ctx->prop.trans = new_trans; - /* update trans_cur (by offset) */ - offset = (char *)(new_trans) - (char *)(old_trans); - - { - char *cctx = (char *)(ctx->trans_cur); - - cctx += offset; - ctx->trans_cur = (struct db_trans *)cctx; - } - /* update elem count */ - ctx->max_trans = max_trans; - PFREE_ST(old_trans, db_trans_st); - ret = 0; -out: - return ret; -} -/* - * Expand storage for attributes by delta_attrs number AND - * rewrite trans->attr pointers - */ -static int -db_attrs_expand(struct db_context *ctx, int delta_attrs) -{ - int ret = -1; - struct db_attr *new_attrs, *old_attrs; - struct db_trans *t; - int ti; - int max_attrs = ctx->max_attrs + delta_attrs; - int offset; - - old_attrs = ctx->attrs0; - new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs, - db_attrs_st); - if (!new_attrs) - goto out; - - memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr)); - - /* update attrs0 and attrs_cur (obviously) */ - offset = (char *)(new_attrs) - (char *)(old_attrs); - - { - char *actx = (char *)(ctx->attrs0); - - actx += offset; - ctx->attrs0 = (struct db_attr *)actx; - - actx = (char *)ctx->attrs_cur; - actx += offset; - ctx->attrs_cur = (struct db_attr *)actx; - } - - /* for each transform, rewrite attrs pointer by offsetting it */ - for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) { - char *actx = (char *)(t->attrs); - - actx += offset; - t->attrs = (struct db_attr *)actx; - } - /* update elem count */ - ctx->max_attrs = max_attrs; - PFREE_ST(old_attrs, db_attrs_st); - ret = 0; -out: - return ret; -} -/* Allocate a new db object */ -struct db_context * -db_prop_new(u_int8_t protoid, int max_trans, int max_attrs) -{ - struct db_context *ctx; - ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), db_context_st); - if (!ctx) goto out; - - if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) { - PFREE_ST(ctx, db_context_st); - ctx=NULL; - } -out: - return ctx; -} -/* Free a db object */ -void -db_destroy(struct db_context *ctx) -{ - if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st); - if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st); - PFREE_ST(ctx, db_context_st); -} -/* Start a new transform, expand trans0 is needed */ -int -db_trans_add(struct db_context *ctx, u_int8_t transid) -{ - /* skip incrementing current trans pointer the 1st time*/ - if (ctx->trans_cur && ctx->trans_cur->attr_cnt) - ctx->trans_cur++; - /* - * Strategy: if more space is needed, expand by - * /2 + 1 - * - * This happens to produce a "reasonable" sequence - * after few allocations, eg.: - * 0,1,2,4,8,13,20,31,47 - */ - if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) { - /* XXX:jjo if fails should shout and flag it */ - if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0) - return -1; - } - ctx->trans_cur->transid = transid; - ctx->trans_cur->attrs=ctx->attrs_cur; - ctx->trans_cur->attr_cnt = 0; - ctx->prop.trans_cnt++; - return 0; -} -/* Add attr copy to current transform, expanding attrs0 if needed */ -int -db_attr_add(struct db_context *ctx, const struct db_attr *a) -{ - /* - * Strategy: if more space is needed, expand by - * /2 + 1 - */ - if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) { - /* XXX:jjo if fails should shout and flag it */ - if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0) - return -1; - } - *ctx->attrs_cur++=*a; - ctx->trans_cur->attr_cnt++; - return 0; -} -/* Add attr copy (by value) to current transform, - * expanding attrs0 if needed, just calls db_attr_add(). - */ -int -db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val) -{ - struct db_attr attr; - attr.type = type; - attr.val = val; - return db_attr_add (ctx, &attr); -} -#ifndef NO_DB_OPS_STATS -int -db_ops_show_status(void) -{ - whack_log(RC_COMMENT, "stats " __FILE__ ": " - DB_OPS_STATS_DESC " :" - DB_OPS_STATS_STR("context") - DB_OPS_STATS_STR("trans") - DB_OPS_STATS_STR("attrs"), - DB_OPS_STATS_F(db_context_st), - DB_OPS_STATS_F(db_trans_st), - DB_OPS_STATS_F(db_attrs_st) - ); - return 0; -} -#endif /* NO_DB_OPS_STATS */ -/* - * From below to end just testing stuff .... - */ -#ifdef TEST -static void db_prop_print(struct db_prop *p) -{ - struct db_trans *t; - struct db_attr *a; - int ti, ai; - enum_names *n, *n_at, *n_av; - printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid)); - for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) { - switch( t->transid) { - case PROTO_ISAKMP: - n=&isakmp_transformid_names;break; - case PROTO_IPSEC_ESP: - n=&esp_transformid_names;break; - default: - continue; - } - printf(" transid=\"%s\"\n", - enum_name(n, t->transid)); - for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) { - int i; - switch( t->transid) { - case PROTO_ISAKMP: - n_at=&oakley_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - case PROTO_IPSEC_ESP: - n_at=&ipsec_attr_names; - i=a->type|ISAKMP_ATTR_AF_TV; - n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; - break; - default: - continue; - } - printf(" type=\"%s\" value=\"%s\"\n", - enum_name(n_at, i), - enum_name(n_av, a->val)); - } - } - -} -static void db_print(struct db_context *ctx) -{ - printf("trans_cur diff=%d, attrs_cur diff=%d\n", - ctx->trans_cur - ctx->trans0, - ctx->attrs_cur - ctx->attrs0); - db_prop_print(&ctx->prop); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no); -void abort(void); -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - abort(); /* exiting correctly doesn't always work */ -} -int main(void) { - struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024); - db_trans_add(ctx, KEY_IKE); - db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC); - db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5); - db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536); - db_trans_add(ctx, ESP_3DES); - db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1); - db_print(ctx); - db_destroy(ctx); - return 0; -} -#endif diff --git a/src/pluto/db_ops.h b/src/pluto/db_ops.h deleted file mode 100644 index 464c245dd..000000000 --- a/src/pluto/db_ops.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Dynamic db (proposal, transforms, attributes) handling. - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DB_OPS_H -#define _DB_OPS_H - -/* - * Main db object, (quite proposal "oriented") - */ -#ifndef NO_DB_CONTEXT -struct db_context { - struct db_prop prop; /* proposal buffer (not pointer) */ - struct db_trans *trans0; /* transf. list, dynamically sized */ - struct db_trans *trans_cur; /* current transform ptr */ - struct db_attr *attrs0; /* attr. list, dynamically sized */ - struct db_attr *attrs_cur; /* current attribute ptr */ - int max_trans; /* size of trans list */ - int max_attrs; /* size of attrs list */ -}; -/* - * Allocate a new db object - */ -struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs); -/* Initialize object for proposal building */ -int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs); -/* Free all resourses for this db */ -void db_destroy(struct db_context *ctx); - -/* Start a new transform */ -int db_trans_add(struct db_context *ctx, u_int8_t transid); -/* Add a new attribute by copying db_attr content */ -int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr); -/* Add a new attribute by value */ -int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val); - -/* Get proposal from db object */ -static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) { - return &ctx->prop; -} -/* Show stats (allocation, etc) */ -#endif /* NO_DB_CONTEXT */ -int db_ops_show_status(void); -#endif /* _DB_OPS_H */ diff --git a/src/pluto/defs.c b/src/pluto/defs.c deleted file mode 100644 index 7f3a819de..000000000 --- a/src/pluto/defs.c +++ /dev/null @@ -1,145 +0,0 @@ -/* misc. universal things - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -bool -all_zero(const unsigned char *m, size_t len) -{ - size_t i; - - for (i = 0; i != len; i++) - if (m[i] != '\0') - return FALSE; - return TRUE; -} - -/* Note that there may be as many as six IDs that are temporary at - * one time before unsharing the two ends of a connection. So we need - * at least six temporary buffers for DER_ASN1_DN IDs. - * We rotate them. Be careful! - */ -#define MAX_BUF 10 - -char* -temporary_cyclic_buffer(void) -{ - static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */ - static int counter = 0; /* cyclic counter */ - - if (++counter == MAX_BUF) counter = 0; /* next internal buffer */ - return buf[counter]; /* assign temporary buffer */ -} - -/* concatenates two sub paths into a string with a maximum size of BUF_LEN - * use for temporary storage only - */ -char* concatenate_paths(char *a, char *b) -{ - char *c; - - if (*b == '/' || *b == '.') - return b; - - c = temporary_cyclic_buffer(); - snprintf(c, BUF_LEN, "%s/%s", a, b); - return c; -} - -/* moves a chunk to a memory position, chunk is freed afterwards - * position pointer is advanced after the insertion point - */ -void -mv_chunk(u_char **pos, chunk_t content) -{ - if (content.len > 0) - { - chunkcpy(*pos, content); - free(content.ptr); - } -} - -/* checks if the expiration date has been reached and - * warns during the warning_interval of the imminent - * expiry. strict=TRUE declares a fatal error, - * strict=FALSE issues a warning upon expiry. - */ -const char* -check_expiry(time_t expiration_date, int warning_interval, bool strict) -{ - time_t now, time_left; - - if (expiration_date == UNDEFINED_TIME) - return "ok (expires never)"; - - /* determine the current time */ - time(&now); - - time_left = (expiration_date - now); - if (time_left < 0) - return strict? "fatal (expired)" : "warning (expired)"; - - if (time_left > 86400*warning_interval) - return "ok"; - { - static char buf[35]; /* temporary storage */ - const char* unit = "second"; - - if (time_left > 172800) - { - time_left /= 86400; - unit = "day"; - } - else if (time_left > 7200) - { - time_left /= 3600; - unit = "hour"; - } - else if (time_left > 120) - { - time_left /= 60; - unit = "minute"; - } - snprintf(buf, 35, "warning (expires in %" PRIu64 " %s%s)", - (u_int64_t)time_left, unit, (time_left == 1) ? "" : "s"); - return buf; - } -} - - -/* - * Filter eliminating the directory entries '.' and '..' - */ -int -file_select(const struct dirent *entry) -{ - return strcmp(entry->d_name, "." ) && - strcmp(entry->d_name, ".."); -} - - diff --git a/src/pluto/defs.h b/src/pluto/defs.h deleted file mode 100644 index 532652e5b..000000000 --- a/src/pluto/defs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* misc. universal things - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEFS_H -#define _DEFS_H - -#include -#include - -#include - -#ifdef DEBUG -# define USED_BY_DEBUG /* ignore */ -#else -# define USED_BY_DEBUG UNUSED -#endif - -/* type of serial number of a state object - * Needed in connections.h and state.h; here to simplify dependencies. - */ -typedef unsigned long so_serial_t; -#define SOS_NOBODY 0 /* null serial number */ -#define SOS_FIRST 1 /* first normal serial number */ - -/* memory allocation */ - -#define clone_thing(orig) clalloc((void *)&(orig), sizeof(orig)) - -#define clone_str(str) \ - ((str) == NULL? NULL : strdup(str)) - -#define replace(p, q) \ - { free(p); (p) = (q); } - -#define chunkcpy(dst, chunk) \ - { memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;} - -extern char* temporary_cyclic_buffer(void); -extern char* concatenate_paths(char *a, char *b); - -/* move a chunk to a memory position and free it after insertion */ -extern void mv_chunk(u_char **pos, chunk_t content); - -/* warns a predefined interval before expiry */ -extern const char* check_expiry(time_t expiration_date, - int warning_interval, bool strict); - -#define MAX_PROMPT_PASS_TRIALS 5 -#define PROMPT_PASS_LEN 64 - -/* filter eliminating the directory entries '.' and '..' */ -typedef struct dirent dirent_t; -extern int file_select(const dirent_t *entry); - -/* cleanly exit Pluto */ -extern void exit_pluto(int /*status*/) NEVER_RETURNS; - -/* zero all bytes */ -#define zero(x) memset((x), '\0', sizeof(*(x))) - -/* are all bytes 0? */ -extern bool all_zero(const unsigned char *m, size_t len); - -/* pad_up(n, m) is the amount to add to n to make it a multiple of m */ -#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m))) - -#endif /* _DEFS_H */ diff --git a/src/pluto/demux.c b/src/pluto/demux.c deleted file mode 100644 index 612e0813c..000000000 --- a/src/pluto/demux.c +++ /dev/null @@ -1,2527 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/* Ordering Constraints on Payloads - * - * rfc2409: The Internet Key Exchange (IKE) - * - * 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - * - * "Except where otherwise noted, there are no requirements for ISAKMP - * payloads in any message to be in any particular order." - * - * 5.3 Phase 1 Authenticated With a Revised Mode of Public Key Encryption: - * - * "If the HASH payload is sent it MUST be the first payload of the - * second message exchange and MUST be followed by the encrypted - * nonce. If the HASH payload is not sent, the first payload of the - * second message exchange MUST be the encrypted nonce." - * - * "Save the requirements on the location of the optional HASH payload - * and the mandatory nonce payload there are no further payload - * requirements. All payloads-- in whatever order-- following the - * encrypted nonce MUST be encrypted with Ke_i or Ke_r depending on the - * direction." - * - * 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - -/* Unfolding of Identity -- a central mystery - * - * This concerns Phase 1 identities, those of the IKE hosts. - * These are the only ones that are authenticated. Phase 2 - * identities are for IPsec SAs. - * - * There are three case of interest: - * - * (1) We initiate, based on a whack command specifying a Connection. - * We know the identity of the peer from the Connection. - * - * (2) (to be implemented) we initiate based on a flow from our client - * to some IP address. - * We immediately know one of the peer's client IP addresses from - * the flow. We must use this to figure out the peer's IP address - * and Id. To be solved. - * - * (3) We respond to an IKE negotiation. - * We immediately know the peer's IP address. - * We get an ID Payload in Main I2. - * - * Unfortunately, this is too late for a number of things: - * - the ISAKMP SA proposals have already been made (Main I1) - * AND one accepted (Main R1) - * - the SA includes a specification of the type of ID - * authentication so this is negotiated without being told the ID. - * - with Preshared Key authentication, Main I2 is encrypted - * using the key, so it cannot be decoded to reveal the ID - * without knowing (or guessing) which key to use. - * - * There are three reasonable choices here for the responder: - * + assume that the initiator is making wise offers since it - * knows the IDs involved. We can balk later (but not gracefully) - * when we find the actual initiator ID - * + attempt to infer identity by IP address. Again, we can balk - * when the true identity is revealed. Actually, it is enough - * to infer properties of the identity (eg. SA properties and - * PSK, if needed). - * + make all properties universal so discrimination based on - * identity isn't required. For example, always accept the same - * kinds of encryption. Accept Public Key Id authentication - * since the Initiator presumably has our public key and thinks - * we must have / can find his. This approach is weakest - * for preshared key since the actual key must be known to - * decrypt the Initiator's ID Payload. - * These choices can be blended. For example, a class of Identities - * can be inferred, sufficient to select a preshared key but not - * sufficient to infer a unique identity. - */ - -#include -#include -#include -#include -#include -#include -#include -#include /* only used for belt-and-suspenders select call */ -#include /* only used for forensic poll call */ -#include -#include -#include -#include -#include - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -# include /* for __u8, __u32 */ -# include -# include /* struct iovec */ -#endif - -#include - -#include "constants.h" -#include "defs.h" -#include "cookie.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "crypto.h" -#include "ike_alg.h" -#include "log.h" -#include "demux.h" /* needs packet.h */ -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "timer.h" -#include "whack.h" /* requires connections.h */ -#include "server.h" -#include "nat_traversal.h" -#include "vendor.h" -#include "modecfg.h" - -/* This file does basic header checking and demux of - * incoming packets. - */ - -/* forward declarations */ -static bool read_packet(struct msg_digest *md); -static void process_packet(struct msg_digest **mdp); - -/* Reply messages are built in this buffer. - * Only one state transition function can be using it at a time - * so suspended STFs must save and restore it. - * It could be an auto variable of complete_state_transition except for the fact - * that when a suspended STF resumes, its reply message buffer - * must be at the same location -- there are pointers into it. - */ -u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* state_microcode is a tuple of information parameterizing certain - * centralized processing of a packet. For example, it roughly - * specifies what payloads are expected in this message. - * The microcode is selected primarily based on the state. - * In Phase 1, the payload structure often depends on the - * authentication technique, so that too plays a part in selecting - * the state_microcode to use. - */ - -struct state_microcode { - enum state_kind state, next_state; - lset_t flags; - lset_t req_payloads; /* required payloads (allows just one) */ - lset_t opt_payloads; /* optional payloads (any mumber) */ - /* if not ISAKMP_NEXT_NONE, process_packet will emit HDR with this as np */ - u_int8_t first_out_payload; - enum event_type timeout_event; - state_transition_fn *processor; -}; - -/* State Microcode Flags, in several groups */ - -/* Oakley Auth values: to which auth values does this entry apply? - * Most entries will use SMF_ALL_AUTH because they apply to all. - * Note: SMF_ALL_AUTH matches 0 for those circumstances when no auth - * has been set. - */ -#define SMF_ALL_AUTH LRANGE(0, OAKLEY_AUTH_ROOF-1) -#define SMF_PSK_AUTH LELEM(OAKLEY_PRESHARED_KEY) -#define SMF_DS_AUTH (LELEM(OAKLEY_DSS_SIG) | LELEM(OAKLEY_RSA_SIG) | \ - LELEM(OAKLEY_ECDSA_SIG) | LELEM(OAKLEY_ECDSA_256) | \ - LELEM(OAKLEY_ECDSA_384) | LELEM(OAKLEY_ECDSA_521)) -#define SMF_PKE_AUTH (LELEM(OAKLEY_RSA_ENC) | LELEM(OAKLEY_ELGAMAL_ENC)) -#define SMF_RPKE_AUTH (LELEM(OAKLEY_RSA_ENC_REV) | LELEM(OAKLEY_ELGAMAL_ENC_REV)) - -/* misc flags */ - -#define SMF_INITIATOR LELEM(OAKLEY_AUTH_ROOF + 0) -#define SMF_FIRST_ENCRYPTED_INPUT LELEM(OAKLEY_AUTH_ROOF + 1) -#define SMF_INPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 2) -#define SMF_OUTPUT_ENCRYPTED LELEM(OAKLEY_AUTH_ROOF + 3) -#define SMF_RETRANSMIT_ON_DUPLICATE LELEM(OAKLEY_AUTH_ROOF + 4) - -#define SMF_ENCRYPTED (SMF_INPUT_ENCRYPTED | SMF_OUTPUT_ENCRYPTED) - -/* this state generates a reply message */ -#define SMF_REPLY LELEM(OAKLEY_AUTH_ROOF + 5) - -/* this state completes P1, so any pending P2 negotiations should start */ -#define SMF_RELEASE_PENDING_P2 LELEM(OAKLEY_AUTH_ROOF + 6) - -/* end of flags */ - - -static state_transition_fn /* forward declaration */ - unexpected, - informational; - -/* state_microcode_table is a table of all state_microcode tuples. - * It must be in order of state (the first element). - * After initialization, ike_microcode_index[s] points to the - * first entry in state_microcode_table for state s. - * Remember that each state name in Main or Quick Mode describes - * what has happened in the past, not what this message is. - */ - -static const struct state_microcode - *ike_microcode_index[STATE_IKE_ROOF - STATE_IKE_FLOOR]; - -static const struct state_microcode state_microcode_table[] = { -#define PT(n) ISAKMP_NEXT_##n -#define P(n) LELEM(PT(n)) - - /***** Phase 1 Main Mode *****/ - - /* No state for main_outI1: --> HDR, SA */ - - /* STATE_MAIN_R0: I1 --> R1 - * HDR, SA --> HDR, SA - */ - { STATE_MAIN_R0, STATE_MAIN_R1 - , SMF_ALL_AUTH | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) - , EVENT_RETRANSMIT, main_inI1_outR1}, - - /* STATE_MAIN_I1: R1 --> I2 - * HDR, SA --> auth dependent - * SMF_PSK_AUTH, SMF_DS_AUTH: --> HDR, KE, Ni - * SMF_PKE_AUTH: - * --> HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * SMF_RPKE_AUTH: - * --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * Note: since we don't know auth at start, we cannot differentiate - * microcode entries based on it. - */ - { STATE_MAIN_I1, STATE_MAIN_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_REPLY - , P(SA), P(VID) | P(CR), PT(NONE) /* don't know yet */ - , EVENT_RETRANSMIT, main_inR1_outI2 }, - - /* STATE_MAIN_R1: I2 --> R2 - * SMF_PSK_AUTH, SMF_DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * SMF_PKE_AUTH: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i - * SMF_RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, Ke_r - */ - { STATE_MAIN_R1, STATE_MAIN_R2 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(KE) - , EVENT_RETRANSMIT, main_inI2_outR2 }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR) | P(HASH), PT(KE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_R1, STATE_UNDEFINED - , SMF_RPKE_AUTH | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR) | P(HASH) | P(CERT), PT(NONCE) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, output message must be encrypted */ - - /* STATE_MAIN_I2: R2 --> I3 - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * SMF_PKE_AUTH: HDR, KE, PubKey_i, PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, Ke_r - * --> HDR*, HASH_I - */ - { STATE_MAIN_I2, STATE_MAIN_I3 - , SMF_PSK_AUTH | SMF_DS_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(NONCE), P(VID) | P(CR) | P(NATD_RFC), PT(ID) - , EVENT_RETRANSMIT, main_inR2_outI3 }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(KE) | P(ID) | P(NONCE), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - { STATE_MAIN_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_OUTPUT_ENCRYPTED | SMF_REPLY - , P(NONCE) | P(KE) | P(ID), P(VID) | P(CR), PT(HASH) - , EVENT_RETRANSMIT, unexpected /* ??? not yet implemented */ }, - - /* for states from here on, input message must be encrypted */ - - /* STATE_MAIN_R2: I3 --> R3 - * SMF_PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * SMF_DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - */ - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_MAIN_R3 - , SMF_DS_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inI3_outR3 }, - - { STATE_MAIN_R2, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED - | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_I3: R3 --> done - * SMF_PSK_AUTH: HDR*, IDr1, HASH_R --> done - * SMF_DS_AUTH: HDR*, IDr1, [ CERT, ] SIG_R --> done - * SMF_PKE_AUTH, SMF_RPKE_AUTH: HDR*, HASH_R --> done - * May initiate quick mode by calling quick_outI1 - */ - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_PSK_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_MAIN_I4 - , SMF_DS_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ID) | P(SIG), P(VID) | P(CR) | P(CERT), PT(NONE) - , EVENT_SA_REPLACE, main_inR3 }, - - { STATE_MAIN_I3, STATE_UNDEFINED - , SMF_PKE_AUTH | SMF_RPKE_AUTH | SMF_INITIATOR - | SMF_FIRST_ENCRYPTED_INPUT | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(HASH), P(VID) | P(CR), PT(NONE) - , EVENT_SA_REPLACE, unexpected /* ??? not yet implemented */ }, - - /* STATE_MAIN_R3: can only get here due to packet loss */ - { STATE_MAIN_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - /* STATE_MAIN_I4: can only get here due to packet loss */ - { STATE_MAIN_I4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED - , LEMPTY, LEMPTY - , PT(NONE), EVENT_NULL, unexpected }, - - - /***** Phase 2 Quick Mode *****/ - - /* No state for quick_outI1: - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - */ - - /* STATE_QUICK_R0: - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * Installs inbound IPsec SAs. - * Because it may suspend for asynchronous DNS, first_out_payload - * is set to NONE to suppress early emission of HDR*. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_R0, STATE_QUICK_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(NONE) - , EVENT_RETRANSMIT, quick_inI1_outR1 }, - - /* STATE_QUICK_I1: - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * Installs inbound and outbound IPsec SAs, routing, etc. - * ??? it is legal to have multiple SAs, but we don't support it yet. - */ - { STATE_QUICK_I1, STATE_QUICK_I2 - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_REPLY - , P(HASH) | P(SA) | P(NONCE), /* P(SA) | */ P(KE) | P(ID) | P(NATOA_RFC), PT(HASH) - , EVENT_SA_REPLACE, quick_inR1_outI2 }, - - /* STATE_QUICK_R1: HDR*, HASH(3) --> done - * Installs outbound IPsec SAs, routing, etc. - */ - { STATE_QUICK_R1, STATE_QUICK_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_SA_REPLACE, quick_inI2 }, - - /* STATE_QUICK_I2: can only happen due to lost packet */ - { STATE_QUICK_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_INITIATOR | SMF_ENCRYPTED | SMF_RETRANSMIT_ON_DUPLICATE - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* STATE_QUICK_R2: can only happen due to lost packet */ - { STATE_QUICK_R2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - - /***** informational messages *****/ - - /* STATE_INFO: */ - { STATE_INFO, STATE_UNDEFINED - , SMF_ALL_AUTH - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* STATE_INFO_PROTECTED: */ - { STATE_INFO_PROTECTED, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(HASH), LEMPTY, PT(NONE) - , EVENT_NULL, informational }, - - /* XAUTH state transitions */ - { STATE_XAUTH_I0, STATE_XAUTH_I1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inI0 }, - - { STATE_XAUTH_R1, STATE_XAUTH_R2 - , SMF_ALL_AUTH | SMF_ENCRYPTED - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_RETRANSMIT, xauth_inR1 }, - - { STATE_XAUTH_I1, STATE_XAUTH_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, xauth_inI1 }, - - { STATE_XAUTH_R2, STATE_XAUTH_R3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(NONE) - , EVENT_SA_REPLACE, xauth_inR2 }, - - { STATE_XAUTH_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_XAUTH_R3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg pull mode state transitions */ - - { STATE_MODE_CFG_R0, STATE_MODE_CFG_R1 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR0 }, - - { STATE_MODE_CFG_I1, STATE_MODE_CFG_I2 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI1 }, - - { STATE_MODE_CFG_R1, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_I2, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - /* ModeCfg push mode state transitions */ - - { STATE_MODE_CFG_I0, STATE_MODE_CFG_I3 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_REPLY | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inI0 }, - - { STATE_MODE_CFG_R3, STATE_MODE_CFG_R4 - , SMF_ALL_AUTH | SMF_ENCRYPTED | SMF_RELEASE_PENDING_P2 - , P(ATTR) | P(HASH), P(VID), PT(HASH) - , EVENT_SA_REPLACE, modecfg_inR3 }, - - { STATE_MODE_CFG_I3, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - - { STATE_MODE_CFG_R4, STATE_UNDEFINED - , SMF_ALL_AUTH | SMF_ENCRYPTED - , LEMPTY, LEMPTY, PT(NONE) - , EVENT_NULL, unexpected }, - -#undef P -#undef PT -}; - -void -init_demux(void) -{ - /* fill ike_microcode_index: - * make ike_microcode_index[s] point to first entry in - * state_microcode_table for state s (backward scan makes this easier). - * Check that table is in order -- catch coding errors. - * For what it's worth, this routine is idempotent. - */ - const struct state_microcode *t; - - for (t = &state_microcode_table[countof(state_microcode_table) - 1];;) - { - passert(STATE_IKE_FLOOR <= t->state && t->state < STATE_IKE_ROOF); - ike_microcode_index[t->state - STATE_IKE_FLOOR] = t; - if (t == state_microcode_table) - break; - t--; - passert(t[0].state <= t[1].state); - } -} - -/* Process any message on the MSG_ERRQUEUE - * - * This information is generated because of the IP_RECVERR socket option. - * The API is sparsely documented, and may be LINUX-only, and only on - * fairly recent versions at that (hence the conditional compilation). - * - * - ip(7) describes IP_RECVERR - * - recvmsg(2) describes MSG_ERRQUEUE - * - readv(2) describes iovec - * - cmsg(3) describes how to process auxiliary messages - * - * ??? we should link this message with one we've sent - * so that the diagnostic can refer to that negotiation. - * - * ??? how long can the messge be? - * - * ??? poll(2) has a very incomplete description of the POLL* events. - * We assume that POLLIN, POLLOUT, and POLLERR are all we need to deal with - * and that POLLERR will be on iff there is a MSG_ERRQUEUE message. - * - * We have to code around a couple of surprises: - * - * - Select can say that a socket is ready to read from, and - * yet a read will hang. It turns out that a message available on the - * MSG_ERRQUEUE will cause select to say something is pending, but - * a normal read will hang. poll(2) can tell when a MSG_ERRQUEUE - * message is pending. - * - * This is dealt with by calling check_msg_errqueue after select - * has indicated that there is something to read, but before the - * read is performed. check_msg_errqueue will return TRUE if there - * is something left to read. - * - * - A write to a socket may fail because there is a pending MSG_ERRQUEUE - * message, without there being anything wrong with the write. This - * makes for confusing diagnostics. - * - * To avoid this, we call check_msg_errqueue before a write. True, - * there is a race condition (a MSG_ERRQUEUE message might arrive - * between the check and the write), but we should eliminate many - * of the problematic events. To narrow the window, the poll(2) - * will await until an event happens (in the case or a write, - * POLLOUT; this should be benign for POLLIN). - */ - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) -static bool -check_msg_errqueue(const struct iface *ifp, short interest) -{ - struct pollfd pfd; - - pfd.fd = ifp->fd; - pfd.events = interest | POLLPRI | POLLOUT; - - while (pfd.revents = 0 - , poll(&pfd, 1, -1) > 0 && (pfd.revents & POLLERR)) - { - u_int8_t buffer[3000]; /* hope that this is big enough */ - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - - int from_len = sizeof(from); - - int packet_len; - - struct msghdr emh; - struct iovec eiov; - union { - /* force alignment (not documented as necessary) */ - struct cmsghdr ecms; - - /* how much space is enough? */ - unsigned char space[256]; - } ecms_buf; - - struct cmsghdr *cm; - char fromstr[sizeof(" for message to port 65536") + INET6_ADDRSTRLEN]; - struct state *sender = NULL; - - zero(&from.sa); - from_len = sizeof(from); - - emh.msg_name = &from.sa; /* ??? filled in? */ - emh.msg_namelen = sizeof(from); - emh.msg_iov = &eiov; - emh.msg_iovlen = 1; - emh.msg_control = &ecms_buf; - emh.msg_controllen = sizeof(ecms_buf); - emh.msg_flags = 0; - - eiov.iov_base = buffer; /* see readv(2) */ - eiov.iov_len = sizeof(buffer); - - packet_len = recvmsg(ifp->fd, &emh, MSG_ERRQUEUE); - - if (packet_len == -1) - { - log_errno((e, "recvmsg(,, MSG_ERRQUEUE) on %s failed in comm_handle" - , ifp->rname)); - break; - } - else if (packet_len == sizeof(buffer)) - { - plog("MSG_ERRQUEUE message longer than %lu bytes; truncated" - , (unsigned long) sizeof(buffer)); - } - else - { - sender = find_sender((size_t) packet_len, buffer); - } - - DBG_cond_dump(DBG_ALL, "rejected packet:\n", buffer, packet_len); - DBG_cond_dump(DBG_ALL, "control:\n", emh.msg_control, emh.msg_controllen); - /* ??? Andi Kleen and misc documentation - * suggests that name will have the original destination - * of the packet. We seem to see msg_namelen == 0. - * Andi says that this is a kernel bug and has fixed it. - * Perhaps in 2.2.18/2.4.0. - */ - passert(emh.msg_name == &from.sa); - DBG_cond_dump(DBG_ALL, "name:\n", emh.msg_name - , emh.msg_namelen); - - fromstr[0] = '\0'; /* usual case :-( */ - switch (from.sa.sa_family) - { - char as[INET6_ADDRSTRLEN]; - - case AF_INET: - if (emh.msg_namelen == sizeof(struct sockaddr_in)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in4.sin_addr, as, sizeof(as)) - , ntohs(from.sa_in4.sin_port)); - break; - case AF_INET6: - if (emh.msg_namelen == sizeof(struct sockaddr_in6)) - snprintf(fromstr, sizeof(fromstr) - , " for message to %s port %u" - , inet_ntop(from.sa.sa_family - , &from.sa_in6.sin6_addr, as, sizeof(as)) - , ntohs(from.sa_in6.sin6_port)); - break; - } - - for (cm = CMSG_FIRSTHDR(&emh) - ; cm != NULL - ; cm = CMSG_NXTHDR(&emh,cm)) - { - if (cm->cmsg_level == SOL_IP - && cm->cmsg_type == IP_RECVERR) - { - /* ip(7) and recvmsg(2) specify: - * ee_origin is SO_EE_ORIGIN_ICMP for ICMP - * or SO_EE_ORIGIN_LOCAL for locally generated errors. - * ee_type and ee_code are from the ICMP header. - * ee_info is the discovered MTU for EMSGSIZE errors - * ee_data is not used. - * - * ??? recvmsg(2) says "SOCK_EE_OFFENDER" but - * means "SO_EE_OFFENDER". The OFFENDER is really - * the router that complained. As such, the port - * is meaningless. - */ - - /* ??? cmsg(3) claims that CMSG_DATA returns - * void *, but RFC 2292 and /usr/include/bits/socket.h - * say unsigned char *. The manual is being fixed. - */ - struct sock_extended_err *ee = (void *)CMSG_DATA(cm); - const char *offstr = "unspecified"; - char offstrspace[INET6_ADDRSTRLEN]; - char orname[50]; - - if (cm->cmsg_len > CMSG_LEN(sizeof(struct sock_extended_err))) - { - const struct sockaddr *offender = SO_EE_OFFENDER(ee); - - switch (offender->sa_family) - { - case AF_INET: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in *)offender)->sin_addr - , offstrspace, sizeof(offstrspace)); - break; - case AF_INET6: - offstr = inet_ntop(offender->sa_family - , &((const struct sockaddr_in6 *)offender)->sin6_addr - , offstrspace, sizeof(offstrspace)); - break; - default: - offstr = "unknown"; - break; - } - } - - switch (ee->ee_origin) - { - case SO_EE_ORIGIN_NONE: - snprintf(orname, sizeof(orname), "none"); - break; - case SO_EE_ORIGIN_LOCAL: - snprintf(orname, sizeof(orname), "local"); - break; - case SO_EE_ORIGIN_ICMP: - snprintf(orname, sizeof(orname) - , "ICMP type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - case SO_EE_ORIGIN_ICMP6: - snprintf(orname, sizeof(orname) - , "ICMP6 type %d code %d (not authenticated)" - , ee->ee_type, ee->ee_code - ); - break; - default: - snprintf(orname, sizeof(orname), "invalid origin %lu" - , (unsigned long) ee->ee_origin); - break; - } - - { - struct state *old_state = cur_state; - - cur_state = sender; - - /* note dirty trick to suppress ~ at start of format - * if we know what state to blame. - */ - if ((packet_len == 1) && (buffer[0] == 0xff) -#ifdef DEBUG - && ((cur_debugging & DBG_NATT) == 0) -#endif - ) { - /* don't log NAT-T keepalive related errors unless NATT debug is - * enabled - */ - } - else - plog((sender != NULL) + "~" - "ERROR: asynchronous network error report on %s" - "%s" - ", complainant %s" - ": %s" - " [errno %lu, origin %s" - /* ", pad %d, info %ld" */ - /* ", data %ld" */ - "]" - , ifp->rname - , fromstr - , offstr - , strerror(ee->ee_errno) - , (unsigned long) ee->ee_errno - , orname - /* , ee->ee_pad, (unsigned long)ee->ee_info */ - /* , (unsigned long)ee->ee_data */ - ); - cur_state = old_state; - } - } - else - { - /* .cmsg_len is a kernel_size_t(!), but the value - * certainly ought to fit in an unsigned long. - */ - plog("unknown cmsg: level %d, type %d, len %lu" - , cm->cmsg_level, cm->cmsg_type - , (unsigned long) cm->cmsg_len); - } - } - } - return (pfd.revents & interest) != 0; -} -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - -bool -send_packet(struct state *st, const char *where) -{ - connection_t *c = st->st_connection; - int port_buf; - bool err; - u_int8_t ike_pkt[MAX_OUTPUT_UDP_SIZE]; - u_int8_t *ptr; - unsigned long len; - - if (c->interface->ike_float && st->st_tpacket.len != 1) - { - if ((unsigned long) st->st_tpacket.len > (MAX_OUTPUT_UDP_SIZE-sizeof(u_int32_t))) - { - DBG_log("send_packet(): really too big"); - return FALSE; - } - ptr = ike_pkt; - /** Add Non-ESP marker **/ - memset(ike_pkt, 0, sizeof(u_int32_t)); - memcpy(ike_pkt + sizeof(u_int32_t), st->st_tpacket.ptr, - (unsigned long)st->st_tpacket.len); - len = (unsigned long) st->st_tpacket.len + sizeof(u_int32_t); - } - else - { - ptr = st->st_tpacket.ptr; - len = (unsigned long) st->st_tpacket.len; - } - - DBG(DBG_RAW, - { - DBG_log("sending %lu bytes for %s through %s to %s:%u:" - , (unsigned long) st->st_tpacket.len - , where - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port); - DBG_dump_chunk(NULL, st->st_tpacket); - }); - - /* XXX: Not very clean. We manipulate the port of the ip_address to - * have a port in the sockaddr*, but we retain the original port - * and restore it afterwards. - */ - - port_buf = portof(&c->spd.that.host_addr); - setportof(htons(c->spd.that.host_port), &c->spd.that.host_addr); - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - (void) check_msg_errqueue(c->interface, POLLOUT); -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - err = sendto(c->interface->fd - , ptr, len, 0 - , sockaddrof(&c->spd.that.host_addr) - , sockaddrlenof(&c->spd.that.host_addr)) != (ssize_t)len; - - /* restore port */ - setportof(port_buf, &c->spd.that.host_addr); - - if (err) - { - /* do not log NAT-T Keep Alive packets */ - if (streq(where, "NAT-T Keep Alive")) - return FALSE; - log_errno((e, "sendto on %s to %s:%u failed in %s" - , c->interface->rname - , ip_str(&c->spd.that.host_addr) - , (unsigned)c->spd.that.host_port - , where)); - return FALSE; - } - else - { - return TRUE; - } -} - -static stf_status -unexpected(struct msg_digest *md) -{ - loglog(RC_LOG_SERIOUS, "unexpected message received in state %s" - , enum_name(&state_names, md->st->st_state)); - return STF_IGNORE; -} - -static stf_status -informational(struct msg_digest *md UNUSED) -{ - struct payload_digest *const n_pld = md->chain[ISAKMP_NEXT_N]; - - /* If the Notification Payload is not null... */ - if (n_pld != NULL) - { - pb_stream *const n_pbs = &n_pld->pbs; - struct isakmp_notification *const n = &n_pld->payload.notification; - int disp_len; - char disp_buf[200]; - - /* Switch on Notification Type (enum) */ - switch (n->isan_type) - { - case R_U_THERE: - return dpd_inI_outR(md->st, n, n_pbs); - - case R_U_THERE_ACK: - return dpd_inR(md->st, n, n_pbs); - default: - if (pbs_left(n_pbs) >= sizeof(disp_buf)-1) - disp_len = sizeof(disp_buf)-1; - else - disp_len = pbs_left(n_pbs); - memcpy(disp_buf, n_pbs->cur, disp_len); - disp_buf[disp_len] = '\0'; - break; - } - } - return STF_IGNORE; -} - -/* message digest allocation and deallocation */ - -static struct msg_digest *md_pool = NULL; - -/* free_md_pool is only used to avoid leak reports */ -void -free_md_pool(void) -{ - for (;;) - { - struct msg_digest *md = md_pool; - - if (md == NULL) - break; - md_pool = md->next; - free(md); - } -} - -static struct msg_digest * -malloc_md(void) -{ - struct msg_digest *md = md_pool; - - /* convenient initializer: - * - all pointers NULL - * - .note = NOTHING_WRONG - * - .encrypted = FALSE - */ - static const struct msg_digest blank_md = { - .next = NULL, - }; - - if (md == NULL) - { - md = malloc_thing(struct msg_digest); - zero(md); - } - else - md_pool = md->next; - - *md = blank_md; - md->digest_roof = md->digest; - - /* note: although there may be multiple msg_digests at once - * (due to suspended state transitions), there is a single - * global reply_buffer. It will need to be saved and restored. - */ - init_pbs(&md->reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - return md; -} - -void -release_md(struct msg_digest *md) -{ - chunk_free(&md->raw_packet); - free(md->packet_pbs.start); - md->packet_pbs.start = NULL; - md->next = md_pool; - md_pool = md; -} - -/* wrapper for read_packet and process_packet - * - * The main purpose of this wrapper is to factor out teardown code - * from the many return points in process_packet. This amounts to - * releasing the msg_digest and resetting global variables. - * - * When processing of a packet is suspended (STF_SUSPEND), - * process_packet sets md to NULL to prevent the msg_digest being freed. - * Someone else must ensure that msg_digest is freed eventually. - * - * read_packet is broken out to minimize the lifetime of the - * enormous input packet buffer, an auto. - */ -void -comm_handle(const struct iface *ifp) -{ - static struct msg_digest *md; - -#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) - /* Even though select(2) says that there is a message, - * it might only be a MSG_ERRQUEUE message. At least - * sometimes that leads to a hanging recvfrom. To avoid - * what appears to be a kernel bug, check_msg_errqueue - * uses poll(2) and tells us if there is anything for us - * to read. - * - * This is early enough that teardown isn't required: - * just return on failure. - */ - if (!check_msg_errqueue(ifp, POLLIN)) - return; /* no normal message to read */ -#endif /* defined(IP_RECVERR) && defined(MSG_ERRQUEUE) */ - - md = malloc_md(); - md->iface = ifp; - - if (read_packet(md)) - process_packet(&md); - - if (md != NULL) - release_md(md); - - cur_state = NULL; - reset_cur_connection(); - cur_from = NULL; -} - -/* read the message. - * Since we don't know its size, we read it into - * an overly large buffer and then copy it to a - * new, properly sized buffer. - */ -static bool -read_packet(struct msg_digest *md) -{ - const struct iface *ifp = md->iface; - int packet_len; - u_int8_t *buffer; - u_int8_t *buffer_nat; - union - { - struct sockaddr sa; - struct sockaddr_in sa_in4; - struct sockaddr_in6 sa_in6; - } from; - int from_len = sizeof(from); - err_t from_ugh = NULL; - static const char undisclosed[] = "unknown source"; - - happy(anyaddr(addrtypeof(&ifp->addr), &md->sender)); - zero(&from.sa); - ioctl(ifp->fd, FIONREAD, &packet_len); - buffer = malloc(packet_len); - packet_len = recvfrom(ifp->fd, buffer, packet_len, 0 - , &from.sa, &from_len); - - /* First: digest the from address. - * We presume that nothing here disturbs errno. - */ - if (packet_len == -1 - && from_len == sizeof(from) - && all_zero((const void *)&from.sa, sizeof(from))) - { - /* "from" is untouched -- not set by recvfrom */ - from_ugh = undisclosed; - } - else if (from_len - < (int) (offsetof(struct sockaddr, sa_family) + sizeof(from.sa.sa_family))) - { - from_ugh = "truncated"; - } - else - { - const struct af_info *afi = aftoinfo(from.sa.sa_family); - - if (afi == NULL) - { - from_ugh = "unexpected Address Family"; - } - else if (from_len != (int)afi->sa_sz) - { - from_ugh = "wrong length"; - } - else - { - switch (from.sa.sa_family) - { - case AF_INET: - from_ugh = initaddr((void *) &from.sa_in4.sin_addr - , sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); - md->sender_port = ntohs(from.sa_in4.sin_port); - break; - case AF_INET6: - from_ugh = initaddr((void *) &from.sa_in6.sin6_addr - , sizeof(from.sa_in6.sin6_addr), AF_INET6, &md->sender); - md->sender_port = ntohs(from.sa_in6.sin6_port); - break; - } - } - } - - /* now we report any actual I/O error */ - if (packet_len == -1) - { - if (from_ugh == undisclosed - && errno == ECONNREFUSED) - { - /* Tone down scary message for vague event: - * We get "connection refused" in response to some - * datagram we sent, but we cannot tell which one. - */ - plog("some IKE message we sent has been rejected with ECONNREFUSED (kernel supplied no details)"); - } - else if (from_ugh != NULL) - { - log_errno((e, "recvfrom on %s failed; Pluto cannot decode source sockaddr in rejection: %s" - , ifp->rname, from_ugh)); - } - else - { - log_errno((e, "recvfrom on %s from %s:%u failed" - , ifp->rname - , ip_str(&md->sender), (unsigned)md->sender_port)); - } - free(buffer); - return FALSE; - } - else if (from_ugh != NULL) - { - plog("recvfrom on %s returned malformed source sockaddr: %s" - , ifp->rname, from_ugh); - free(buffer); - return FALSE; - } - cur_from = &md->sender; - cur_from_port = md->sender_port; - - if (ifp->ike_float == TRUE) - { - u_int32_t non_esp; - - if (packet_len < (int)sizeof(u_int32_t)) - { - plog("recvfrom %s:%u too small packet (%d)" - , ip_str(cur_from), (unsigned) cur_from_port, packet_len); - free(buffer); - return FALSE; - } - memcpy(&non_esp, buffer, sizeof(u_int32_t)); - if (non_esp != 0) - { - plog("recvfrom %s:%u has no Non-ESP marker" - , ip_str(cur_from), (unsigned) cur_from_port); - free(buffer); - return FALSE; - } - packet_len -= sizeof(u_int32_t); - buffer_nat = malloc(packet_len); - memcpy(buffer_nat, buffer + sizeof(u_int32_t), packet_len); - free(buffer); - buffer = buffer_nat; - } - - /* Clone actual message contents - * and set up md->packet_pbs to describe it. - */ - init_pbs(&md->packet_pbs, buffer, packet_len, "packet"); - - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL, - { - DBG_log(BLANK_FORMAT); - DBG_log("*received %d bytes from %s:%u on %s" - , (int) pbs_room(&md->packet_pbs) - , ip_str(cur_from), (unsigned) cur_from_port - , ifp->rname); - }); - - DBG(DBG_RAW, - DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs))); - - if ((pbs_room(&md->packet_pbs)==1) && (md->packet_pbs.start[0]==0xff)) - { - /** - * NAT-T Keep-alive packets should be discarded by kernel ESPinUDP - * layer. But bogus keep-alive packets (sent with a non-esp marker) - * can reach this point. Complain and discard them. - */ - DBG(DBG_NATT, - DBG_log("NAT-T keep-alive (bogus ?) should not reach this point. " - "Ignored. Sender: %s:%u", ip_str(cur_from), - (unsigned) cur_from_port); - ) - return FALSE; - } - -#define IKEV2_VERSION_OFFSET 17 -#define IKEV2_VERSION 0x20 - - /* ignore IKEv2 packets - they will be handled by charon */ - if (pbs_room(&md->packet_pbs) > IKEV2_VERSION_OFFSET - && (md->packet_pbs.start[IKEV2_VERSION_OFFSET] & 0xF0) == IKEV2_VERSION) - { - DBG(DBG_CONTROLMORE, - DBG_log(" ignoring IKEv2 packet") - ) - return FALSE; - } - - return TRUE; -} - -/* process an input packet, possibly generating a reply. - * - * If all goes well, this routine eventually calls a state-specific - * transition function. - */ -static void -process_packet(struct msg_digest **mdp) -{ - struct msg_digest *md = *mdp; - const struct state_microcode *smc; - bool new_iv_set = FALSE; - bool restore_iv = FALSE; - u_char new_iv[MAX_DIGEST_LEN]; - u_int new_iv_len = 0; - - struct state *st = NULL; - enum state_kind from_state = STATE_UNDEFINED; /* state we started in */ - -#define SEND_NOTIFICATION(t) { \ - if (st) send_notification_from_state(st, from_state, t); \ - else send_notification_from_md(md, t); } - - if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) - { - /* Identify specific failures: - * - bad ISAKMP major/minor version numbers - */ - if (md->packet_pbs.roof - md->packet_pbs.cur >= (ptrdiff_t)isakmp_hdr_desc.size) - { - struct isakmp_hdr *hdr = (struct isakmp_hdr *)md->packet_pbs.cur; - if ((hdr->isa_version >> ISA_MAJ_SHIFT) != ISAKMP_MAJOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MAJOR_VERSION); - return; - } - else if ((hdr->isa_version & ISA_MIN_MASK) != ISAKMP_MINOR_VERSION) - { - SEND_NOTIFICATION(ISAKMP_INVALID_MINOR_VERSION); - return; - } - } - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - if (md->packet_pbs.roof != md->message_pbs.roof) - { - plog("size (%u) differs from size specified in ISAKMP HDR (%u)" - , (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); -#ifdef CISCO_QUIRKS - if (pbs_room(&md->packet_pbs) - md->hdr.isa_length == 16) - plog("Cisco VPN client appends 16 surplus NULL bytes"); - else -#endif - return; - } - - switch (md->hdr.isa_xchg) - { -#ifdef NOTYET - case ISAKMP_XCHG_NONE: - case ISAKMP_XCHG_BASE: -#endif - - case ISAKMP_XCHG_IDPROT: /* part of a Main Mode exchange */ - if (md->hdr.isa_msgid != MAINMODE_MSGID) - { - plog("Message ID was 0x%08lx but should be zero in Main Mode", - (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Initiator Cookie must not be zero in Main Mode message"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - /* initial message from initiator - * ??? what if this is a duplicate of another message? - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - plog("initial Main Mode message is invalid:" - " its Encrypted Flag is on"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* don't build a state until the message looks tasty */ - from_state = STATE_MAIN_R0; - } - else - { - /* not an initial message */ - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* perhaps this is a first message from the responder - * and contains a responder cookie that we've not yet seen. - */ - st = find_state(md->hdr.isa_icookie, zero_cookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - plog("Main Mode message is part of an unknown exchange"); - /* XXX Could send notification back */ - return; - } - } - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_AO: - case ISAKMP_XCHG_AGGR: -#endif - - case ISAKMP_XCHG_INFO: /* an informational exchange */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st != NULL) - set_cur_state(st); - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - if (st == NULL) - { - plog("Informational Exchange is for an unknown (expired?) SA"); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "encrypted Informational Exchange message is invalid" - " because no key is known"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message is invalid because" - " it has a previously used Message ID (0x%08lx)" - , (unsigned long)md->hdr.isa_msgid); - /* XXX Could send notification back */ - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - memcpy(st->st_ph1_iv, st->st_new_iv, st->st_new_iv_len); - st->st_ph1_iv_len = st->st_new_iv_len; - - /* backup new_iv */ - new_iv_len = st->st_new_iv_len; - passert(new_iv_len <= MAX_DIGEST_LEN) - memcpy(new_iv, st->st_new_iv, new_iv_len); - restore_iv = TRUE; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_INFO_PROTECTED; - } - else - { - if (st != NULL && IS_ISAKMP_ENCRYPTED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Informational Exchange message" - " must be encrypted"); - /* XXX Could send notification back */ - return; - } - from_state = STATE_INFO; - } - break; - - case ISAKMP_XCHG_QUICK: /* part of a Quick Mode exchange */ - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("Quick Mode message is invalid because" - " it has an Initiator Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("Quick Mode message is invalid because" - " it has a Responder Cookie of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_COOKIE); - return; - } - - if (md->hdr.isa_msgid == MAINMODE_MSGID) - { - plog("Quick Mode message is invalid because" - " it has a Message ID of 0"); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - /* No appropriate Quick Mode state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, MAINMODE_MSGID); - - if (st == NULL) - { - plog("Quick Mode message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode message is unacceptable because" - " it is for an incomplete ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - - /* only accept this new Quick Mode exchange if it has a unique message ID */ - if (!reserve_msgid(st, md->hdr.isa_msgid)) - { - loglog(RC_LOG_SERIOUS, "Quick Mode I1 message is unacceptable because" - " it uses a previously used Message ID 0x%08lx" - " (perhaps this is a duplicated packet)" - , (unsigned long) md->hdr.isa_msgid); - SEND_NOTIFICATION(ISAKMP_INVALID_MESSAGE_ID); - return; - } - - /* Quick Mode Initial IV */ - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - from_state = STATE_QUICK_R0; - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - - break; - - case ISAKMP_XCHG_MODE_CFG: - if (is_zero_cookie(md->hdr.isa_icookie)) - { - plog("ModeCfg message is invalid because" - " it has an Initiator Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (is_zero_cookie(md->hdr.isa_rcookie)) - { - plog("ModeCfg message is invalid because" - " it has a Responder Cookie of 0"); - /* XXX Could send notification back */ - return; - } - - if (md->hdr.isa_msgid == 0) - { - plog("ModeCfg message is invalid because" - " it has a Message ID of 0"); - /* XXX Could send notification back */ - return; - } - - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, md->hdr.isa_msgid); - - if (st == NULL) - { - bool has_xauth_policy; - - /* No appropriate ModeCfg state. - * See if we have a Main Mode state. - * ??? what if this is a duplicate of another message? - */ - st = find_state(md->hdr.isa_icookie, md->hdr.isa_rcookie - , &md->sender, 0); - - if (st == NULL) - { - plog("ModeCfg message is for a non-existent (expired?)" - " ISAKMP SA"); - /* XXX Could send notification back */ - return; - } - - set_cur_state(st); - - /* the XAUTH_STATUS message might have a new msgid */ - if (st->st_state == STATE_XAUTH_I1) - { - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - from_state = st->st_state; - break; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "ModeCfg message is unacceptable because" - " it is for an incomplete ISAKMP SA (state=%s)" - , enum_name(&state_names, st->st_state)); - /* XXX Could send notification back */ - return; - } - init_phase2_iv(st, &md->hdr.isa_msgid); - new_iv_set = TRUE; - - /* - * okay, now we have to figure out if we are receiving a bogus - * new message in an outstanding XAUTH server conversation - * (i.e. a reply to our challenge) - * (this occurs with some broken other implementations). - * - * or if receiving for the first time, an XAUTH challenge. - * - * or if we are getting a MODECFG request. - * - * we distinguish these states because we can not both be an - * XAUTH server and client, and our policy tells us which - * one we are. - * - * to complicate further, it is normal to start a new msgid - * when going from one state to another, or when restarting - * the challenge. - * - */ - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - - if (has_xauth_policy && !st->st_xauth.started - && IS_PHASE1(st->st_state)) - { - from_state = STATE_XAUTH_I0; - } - else if (st->st_connection->spd.that.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_R0; - } - else if (st->st_connection->spd.this.modecfg - && IS_PHASE1(st->st_state)) - { - from_state = STATE_MODE_CFG_I0; - } - else - { - /* XXX check if we are being a mode config server here */ - plog("received ModeCfg message when in state %s, and we aren't mode config client" - , enum_name(&state_names, st->st_state)); - return; - } - } - else - { - set_cur_state(st); - from_state = st->st_state; - } - break; - -#ifdef NOTYET - case ISAKMP_XCHG_NGRP: - case ISAKMP_XCHG_ACK_INFO: -#endif - - default: - plog("unsupported exchange type %s in message" - , enum_show(&exchange_names, md->hdr.isa_xchg)); - SEND_NOTIFICATION(ISAKMP_UNSUPPORTED_EXCHANGE_TYPE); - return; - } - - /* We have found a from_state, and perhaps a state object. - * If we need to build a new state object, - * we wait until the packet has been sanity checked. - */ - - /* We don't support the Commit Flag. It is such a bad feature. - * It isn't protected -- neither encrypted nor authenticated. - * A man in the middle turns it on, leading to DoS. - * We just ignore it, with a warning. - * By placing the check here, we could easily add a policy bit - * to a connection to suppress the warning. This might be useful - * because the Commit Flag is expected from some peers. - */ - if (md->hdr.isa_flags & ISAKMP_FLAG_COMMIT) - { - plog("IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag"); - } - - /* Set smc to describe this state's properties. - * Look up the appropriate microcode based on state and - * possibly Oakley Auth type. - */ - passert(STATE_IKE_FLOOR <= from_state && from_state < STATE_IKE_ROOF); - smc = ike_microcode_index[from_state - STATE_IKE_FLOOR]; - - if (st != NULL) - { - u_int16_t auth; - - switch (st->st_oakley.auth) - { - case XAUTHInitPreShared: - case XAUTHRespPreShared: - auth = OAKLEY_PRESHARED_KEY; - break; - case XAUTHInitRSA: - case XAUTHRespRSA: - auth = OAKLEY_RSA_SIG; - break; - default: - auth = st->st_oakley.auth; - } - - while (!LHAS(smc->flags, auth)) - { - smc++; - passert(smc->state == from_state); - } - } - - /* Ignore a packet if the state has a suspended state transition - * Probably a duplicated packet but the original packet is not yet - * recorded in st->st_rpacket, so duplicate checking won't catch. - * ??? Should the packet be recorded earlier to improve diagnosis? - */ - if (st != NULL && st->st_suspended_md != NULL) - { - loglog(RC_LOG, "discarding packet received during DNS lookup in %s" - , enum_name(&state_names, st->st_state)); - return; - } - - /* Detect and handle duplicated packets. - * This won't work for the initial packet of an exchange - * because we won't have a state object to remember it. - * If we are in a non-receiving state (terminal), and the preceding - * state did transmit, then the duplicate may indicate that that - * transmission wasn't received -- retransmit it. - * Otherwise, just discard it. - * ??? Notification packets are like exchanges -- I hope that - * they are idempotent! - */ - if (st != NULL - && st->st_rpacket.ptr != NULL - && st->st_rpacket.len == pbs_room(&md->packet_pbs) - && memeq(st->st_rpacket.ptr, md->packet_pbs.start, st->st_rpacket.len)) - { - if (smc->flags & SMF_RETRANSMIT_ON_DUPLICATE) - { - if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) - { - st->st_retransmit++; - loglog(RC_RETRANSMISSION - , "retransmitting in response to duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - send_packet(st, "retransmit in response to duplicate"); - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet -- exhausted retransmission; already %s" - , enum_name(&state_names, st->st_state)); - } - } - else - { - loglog(RC_LOG_SERIOUS, "discarding duplicate packet; already %s" - , enum_name(&state_names, st->st_state)); - } - return; - } - - if (md->hdr.isa_flags & ISAKMP_FLAG_ENCRYPTION) - { - DBG(DBG_CRYPT, DBG_log("received encrypted packet from %s:%u" - , ip_str(&md->sender), (unsigned)md->sender_port)); - - if (st == NULL) - { - plog("discarding encrypted message for an unknown ISAKMP SA"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED /* XXX ? */); - return; - } - if (st->st_skeyid_e.ptr == (u_char *) NULL) - { - loglog(RC_LOG_SERIOUS, "discarding encrypted message" - " because we haven't yet negotiated keying materiel"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - - /* Mark as encrypted */ - md->encrypted = TRUE; - - DBG(DBG_CRYPT, DBG_log("decrypting %u bytes using algorithm %s" - , (unsigned) pbs_left(&md->message_pbs) - , enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - - /* do the specified decryption - * - * IV is from st->st_iv or (if new_iv_set) st->st_new_iv. - * The new IV is placed in st->st_new_iv - * - * See RFC 2409 "IKE" Appendix B - * - * XXX The IV should only be updated really if the packet - * is successfully processed. - * We should keep this value, check for a success return - * value from the parsing routines and then replace. - * - * Each post phase 1 exchange generates IVs from - * the last phase 1 block, not the last block sent. - */ - { - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - chunk_t data, iv; - char *new_iv; - - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - if (pbs_left(&md->message_pbs) % crypter_block_size != 0) - { - loglog(RC_LOG_SERIOUS, "malformed message: not a multiple of encryption blocksize"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* XXX Detect weak keys */ - - /* grab a copy of raw packet (for duplicate packet detection) */ - md->raw_packet = chunk_create(md->packet_pbs.start, pbs_room(&md->packet_pbs)); - md->raw_packet = chunk_clone(md->raw_packet); - - data = chunk_create(md->message_pbs.cur, pbs_left(&md->message_pbs)); - - /* Decrypt everything after header */ - if (!new_iv_set) - { - /* use old IV */ - passert(st->st_iv_len <= sizeof(st->st_new_iv)); - st->st_new_iv_len = st->st_iv_len; - memcpy(st->st_new_iv, st->st_iv, st->st_new_iv_len); - } - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - new_iv = alloca(crypter_iv_size); - memcpy(new_iv, data.ptr + data.len - crypter_iv_size, - crypter_iv_size); - - crypter->set_key(crypter, st->st_enc_key); - crypter->decrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - if (restore_iv) - { - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_new_iv_len = new_iv_len; - } - } - - DBG_cond_dump(DBG_CRYPT, "decrypted:\n", md->message_pbs.cur - , md->message_pbs.roof - md->message_pbs.cur); - - DBG_cond_dump(DBG_CRYPT, "next IV:" - , st->st_new_iv, st->st_new_iv_len); - } - else - { - /* packet was not encryped -- should it have been? */ - - if (smc->flags & SMF_INPUT_ENCRYPTED) - { - loglog(RC_LOG_SERIOUS, "packet rejected: should have been encrypted"); - SEND_NOTIFICATION(ISAKMP_INVALID_FLAGS); - return; - } - } - - /* Digest the message. - * Padding must be removed to make hashing work. - * Padding comes from encryption (so this code must be after decryption). - * Padding rules are described before the definition of - * struct isakmp_hdr in packet.h. - */ - { - struct payload_digest *pd = md->digest; - int np = md->hdr.isa_np; - lset_t needed = smc->req_payloads; - const char *excuse - = LIN(SMF_PSK_AUTH | SMF_FIRST_ENCRYPTED_INPUT, smc->flags) - ? "probable authentication failure (mismatch of preshared secrets?): " - : ""; - - while (np != ISAKMP_NEXT_NONE) - { - struct_desc *sd = np < ISAKMP_NEXT_ROOF? payload_descs[np] : NULL; - - if (pd == &md->digest[PAYLIMIT]) - { - loglog(RC_LOG_SERIOUS, "more than %d payloads in message; ignored", PAYLIMIT); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - switch (np) - { - case ISAKMP_NEXT_NATD_RFC: - case ISAKMP_NEXT_NATOA_RFC: - if (!st || !(st->nat_traversal & NAT_T_WITH_RFC_VALUES)) - { - /* - * don't accept NAT-D/NAT-OA reloc directly in message, unless - * we're using NAT-T RFC - */ - sd = NULL; - } - break; - } - - if (sd == NULL) - { - /* payload type is out of range or requires special handling */ - switch (np) - { - case ISAKMP_NEXT_ID: - sd = IS_PHASE1(from_state) - ? &isakmp_identification_desc : &isakmp_ipsec_identification_desc; - break; - case ISAKMP_NEXT_NATD_DRAFTS: - np = ISAKMP_NEXT_NATD_RFC; /* NAT-D relocated */ - sd = payload_descs[np]; - break; - case ISAKMP_NEXT_NATOA_DRAFTS: - np = ISAKMP_NEXT_NATOA_RFC; /* NAT-OA relocated */ - sd = payload_descs[np]; - break; - default: - loglog(RC_LOG_SERIOUS, "%smessage ignored because it contains an unknown or" - " unexpected payload type (%s) at the outermost level" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - } - - { - lset_t s = LELEM(np); - - if (LDISJOINT(s - , needed | smc->opt_payloads| LELEM(ISAKMP_NEXT_N) | LELEM(ISAKMP_NEXT_D))) - { - loglog(RC_LOG_SERIOUS, "%smessage ignored because it " - "contains an unexpected payload type (%s)" - , excuse, enum_show(&payload_names, np)); - SEND_NOTIFICATION(ISAKMP_INVALID_PAYLOAD_TYPE); - return; - } - needed &= ~s; - } - - if (!in_struct(&pd->payload, sd, &md->message_pbs, &pd->pbs)) - { - loglog(RC_LOG_SERIOUS, "%smalformed payload in packet", excuse); - if (md->hdr.isa_xchg != ISAKMP_XCHG_INFO) - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - /* place this payload at the end of the chain for this type */ - { - struct payload_digest **p; - - for (p = &md->chain[np]; *p != NULL; p = &(*p)->next) - ; - *p = pd; - pd->next = NULL; - } - - np = pd->payload.generic.isag_np; - pd++; - - /* since we've digested one payload happily, it is probably - * the case that any decryption worked. So we will not suggest - * encryption failure as an excuse for subsequent payload - * problems. - */ - excuse = ""; - } - - md->digest_roof = pd; - - DBG(DBG_PARSING, - if (pbs_left(&md->message_pbs) != 0) - DBG_log("removing %d bytes of padding", (int) pbs_left(&md->message_pbs))); - - md->message_pbs.roof = md->message_pbs.cur; - - /* check that all mandatory payloads appeared */ - - if (needed != 0) - { - loglog(RC_LOG_SERIOUS, "message for %s is missing payloads %s" - , enum_show(&state_names, from_state) - , bitnamesof(payload_name, needed)); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - - /* more sanity checking: enforce most ordering constraints */ - - if (IS_PHASE1(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5 Exchanges: - * "The SA payload MUST precede all other payloads in a phase 1 exchange." - */ - if (md->chain[ISAKMP_NEXT_SA] != NULL - && md->hdr.isa_np != ISAKMP_NEXT_SA) - { - loglog(RC_LOG_SERIOUS, "malformed Phase 1 message: does not start with an SA payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - else if (IS_QUICK(from_state)) - { - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode - * - * "In Quick Mode, a HASH payload MUST immediately follow the ISAKMP - * header and a SA payload MUST immediately follow the HASH." - * [NOTE: there may be more than one SA payload, so this is not - * totally reasonable. Probably all SAs should be so constrained.] - * - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - * - * "With the exception of the HASH, SA, and the optional ID payloads, - * there are no payload ordering restrictions on Quick Mode." - */ - - if (md->hdr.isa_np != ISAKMP_NEXT_HASH) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: does not start with a HASH payload"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - - { - struct payload_digest *p; - int i; - - for (p = md->chain[ISAKMP_NEXT_SA], i = 1; p != NULL - ; p = p->next, i++) - { - if (p != &md->digest[i]) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message: SA payload is in wrong position"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - - /* rfc2409: The Internet Key Exchange (IKE), 5.5 Phase 2 - Quick Mode: - * "If ISAKMP is acting as a client negotiator on behalf of another - * party, the identities of the parties MUST be passed as IDci and - * then IDcr." - */ - { - struct payload_digest *id = md->chain[ISAKMP_NEXT_ID]; - - if (id != NULL) - { - if (id->next == NULL || id->next->next != NULL) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " if any ID payload is present," - " there must be exactly two"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - if (id+1 != id->next) - { - loglog(RC_LOG_SERIOUS, "malformed Quick Mode message:" - " the ID payloads are not adjacent"); - SEND_NOTIFICATION(ISAKMP_PAYLOAD_MALFORMED); - return; - } - } - } - } - - /* Ignore payloads that we don't handle: - * Delete, Notification, VendorID - */ - /* XXX Handle deletions */ - /* XXX Handle Notifications */ - /* XXX Handle VID payloads */ - { - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_N]; p != NULL; p = p->next) - { - if (p->payload.notification.isan_type != R_U_THERE - && p->payload.notification.isan_type != R_U_THERE_ACK) - { - loglog(RC_LOG_SERIOUS, "ignoring informational payload, type %s" - , enum_show(¬ification_names, p->payload.notification.isan_type)); - } - DBG_cond_dump(DBG_PARSING, "info:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_D]; p != NULL; p = p->next) - { - accept_delete(st, md, p); - DBG_cond_dump(DBG_PARSING, "del:", p->pbs.cur, pbs_left(&p->pbs)); - } - - for (p = md->chain[ISAKMP_NEXT_VID]; p != NULL; p = p->next) - { - handle_vendorid(md, p->pbs.cur, pbs_left(&p->pbs)); - } - } - md->from_state = from_state; - md->smc = smc; - md->st = st; - - /* possibly fill in hdr */ - if (smc->first_out_payload != ISAKMP_NEXT_NONE) - echo_hdr(md, (smc->flags & SMF_OUTPUT_ENCRYPTED) != 0 - , smc->first_out_payload); - - complete_state_transition(mdp, smc->processor(md)); -} - -/* complete job started by the state-specific state transition function */ - -void -complete_state_transition(struct msg_digest **mdp, stf_status result) -{ - bool has_xauth_policy; - bool is_xauth_server; - struct msg_digest *md = *mdp; - const struct state_microcode *smc = md->smc; - enum state_kind from_state = md->from_state; - struct state *st; - - cur_state = st = md->st; /* might have changed */ - - /* If state has DPD support, import it */ - if (st && md->dpd) - st->st_dpd = TRUE; - - switch (result) - { - case STF_IGNORE: - break; - - case STF_SUSPEND: - /* the stf didn't complete its job: don't relase md */ - *mdp = NULL; - break; - - case STF_OK: - /* advance the state */ - st->st_state = smc->next_state; - - /* Delete previous retransmission event. - * New event will be scheduled below. - */ - delete_event(st); - - /* replace previous receive packet with latest */ - - free(st->st_rpacket.ptr); - - if (md->encrypted) - { - /* if encrypted, duplication already done */ - st->st_rpacket = md->raw_packet; - md->raw_packet.ptr = NULL; - } - else - { - st->st_rpacket = chunk_create(md->packet_pbs.start, - pbs_room(&md->packet_pbs)); - st->st_rpacket = chunk_clone(st->st_rpacket); - } - - /* free previous transmit packet */ - chunk_free(&st->st_tpacket); - - /* if requested, send the new reply packet */ - if (smc->flags & SMF_REPLY) - { - close_output_pbs(&md->reply); /* good form, but actually a no-op */ - - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - if (nat_traversal_enabled) - nat_traversal_change_port_lookup(md, md->st); - - /* actually send the packet - * Note: this is a great place to implement "impairments" - * for testing purposes. Suppress or duplicate the - * send_packet call depending on st->st_state. - */ - send_packet(st, enum_name(&state_names, from_state)); - } - - /* Schedule for whatever timeout is specified */ - { - time_t delay = UNDEFINED_TIME; - enum event_type kind = smc->timeout_event; - bool agreed_time = FALSE; - connection_t *c = st->st_connection; - - switch (kind) - { - case EVENT_RETRANSMIT: /* Retransmit packet */ - delay = EVENT_RETRANSMIT_DELAY_0; - break; - - case EVENT_SA_REPLACE: /* SA replacement event */ - if (IS_PHASE1(st->st_state)) - { - /* Note: we will defer to the "negotiated" (dictated) - * lifetime if we are POLICY_DONT_REKEY. - * This allows the other side to dictate - * a time we would not otherwise accept - * but it prevents us from having to initiate - * rekeying. The negative consequences seem - * minor. - */ - delay = c->sa_ike_life_seconds; - if ((c->policy & POLICY_DONT_REKEY) - || delay >= st->st_oakley.life_seconds) - { - agreed_time = TRUE; - delay = st->st_oakley.life_seconds; - } - } - else - { - /* Delay is min of up to four things: - * each can limit the lifetime. - */ - delay = c->sa_ipsec_life_seconds; - if (st->st_ah.present - && delay >= st->st_ah.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ah.attrs.life_seconds; - } - if (st->st_esp.present - && delay >= st->st_esp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_esp.attrs.life_seconds; - } - if (st->st_ipcomp.present - && delay >= st->st_ipcomp.attrs.life_seconds) - { - agreed_time = TRUE; - delay = st->st_ipcomp.attrs.life_seconds; - } - } - - /* By default, we plan to rekey. - * - * If there isn't enough time to rekey, plan to - * expire. - * - * If we are --dontrekey, a lot more rules apply. - * If we are the Initiator, use REPLACE_IF_USED. - * If we are the Responder, and the dictated time - * was unacceptable (too large), plan to REPLACE - * (the only way to ratchet down the time). - * If we are the Responder, and the dictated time - * is acceptable, plan to EXPIRE. - * - * Important policy lies buried here. - * For example, we favour the initiator over the - * responder by making the initiator start rekeying - * sooner. Also, fuzz is only added to the - * initiator's margin. - * - * Note: for ISAKMP SA, we let the negotiated - * time stand (implemented by earlier logic). - */ - if (agreed_time - && (c->policy & POLICY_DONT_REKEY)) - { - kind = (smc->flags & SMF_INITIATOR) - ? EVENT_SA_REPLACE_IF_USED - : EVENT_SA_EXPIRE; - } - if (kind != EVENT_SA_EXPIRE) - { - unsigned long marg = c->sa_rekey_margin; - - if (smc->flags & SMF_INITIATOR) - marg += marg - * c->sa_rekey_fuzz / 100.E0 - * (rand() / (RAND_MAX + 1.E0)); - else - marg /= 2; - - if ((unsigned long)delay > marg) - { - delay -= marg; - st->st_margin = marg; - } - else - { - kind = EVENT_SA_EXPIRE; - } - } - break; - - case EVENT_NULL: /* non-event */ - case EVENT_REINIT_SECRET: /* Refresh cookie secret */ - default: - bad_case(kind); - } - event_schedule(kind, delay, st); - } - - /* tell whack and log of progress */ - { - const char *story = state_story[st->st_state]; - enum rc_type w = RC_NEW_STATE + st->st_state; - char sadetails[128]; - - sadetails[0]='\0'; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - char *b = sadetails; - const char *ini = " {"; - const char *fin = ""; - - /* -1 is to leave space for "fin" */ - - if (st->st_esp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sESP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_esp.attrs.spi) - , ntohl(st->st_esp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ah.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sAH=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ah.attrs.spi) - , ntohl(st->st_ah.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_ipcomp.present) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sIPCOMP=>0x%08x <0x%08x" - , ini - , ntohl(st->st_ipcomp.attrs.spi) - , ntohl(st->st_ipcomp.our_spi)); - ini = " "; - fin = "}"; - } - /* advance b to end of string */ - b = b + strlen(b); - - if (st->nat_traversal) - { - char oa[ADDRTOT_BUF]; - addrtot(&st->nat_oa, 0, oa, sizeof(oa)); - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sNATOA=%s" - , ini, oa); - ini = " "; - fin = "}"; - } - - /* advance b to end of string */ - b = b + strlen(b); - - if (st->st_dpd) - { - snprintf(b, sizeof(sadetails)-(b-sadetails)-1 - , "%sDPD" - , ini); - ini = " "; - fin = "}"; - } - - strcat(b, fin); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - /* log our success */ - plog("%s%s", story, sadetails); - w = RC_SUCCESS; - } - - /* tell whack our progress */ - whack_log(w - , "%s: %s%s" - , enum_name(&state_names, st->st_state) - , story, sadetails); - } - - has_xauth_policy = (st->st_connection->policy - & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK)) - != LEMPTY; - is_xauth_server = (st->st_connection->policy - & POLICY_XAUTH_SERVER) - != LEMPTY; - - /* Should we start XAUTH as a server */ - if (has_xauth_policy && is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("starting XAUTH server") - ) - xauth_send_request(st); - break; - } - - /* Wait for XAUTH request from server */ - if (has_xauth_policy && !is_xauth_server - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_xauth.started) - { - DBG(DBG_CONTROL, - DBG_log("waiting for XAUTH request from server") - ) - break; - } - - /* Should we start ModeConfig as a client? */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !(st->st_connection->policy & POLICY_MODECFG_PUSH) - && !st->st_modecfg.started) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg client in pull mode") - ) - modecfg_send_request(st); - break; - } - - /* Should we start ModeConfig as a server? */ - if (st->st_connection->spd.that.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.started - && (st->st_connection->policy & POLICY_MODECFG_PUSH)) - { - DBG(DBG_CONTROL, - DBG_log("starting ModeCfg server in push mode") - ) - modecfg_send_set(st); - break; - } - - /* Wait for ModeConfig set from server */ - if (st->st_connection->spd.this.modecfg - && IS_ISAKMP_SA_ESTABLISHED(st->st_state) - && !st->st_modecfg.vars_set) - { - DBG(DBG_CONTROL, - DBG_log("waiting for ModeCfg set from server") - ) - break; - } - - if (smc->flags & SMF_RELEASE_PENDING_P2) - { - /* Initiate any Quick Mode negotiations that - * were waiting to piggyback on this Keying Channel. - * - * ??? there is a potential race condition - * if we are the responder: the initial Phase 2 - * message might outrun the final Phase 1 message. - * I think that retransmission will recover. - */ - unpend(st); - } - - if (IS_ISAKMP_SA_ESTABLISHED(st->st_state) - || IS_IPSEC_SA_ESTABLISHED(st->st_state)) - release_whack(st); - break; - - case STF_INTERNAL_ERROR: - whack_log(RC_INTERNALERR + md->note - , "%s: internal error" - , enum_name(&state_names, st->st_state)); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s had internal error" - , enum_name(&state_names, from_state))); - break; - - default: /* a shortcut to STF_FAIL, setting md->note */ - passert(result > STF_FAIL); - md->note = result - STF_FAIL; - result = STF_FAIL; - /* FALL THROUGH ... */ - case STF_FAIL: - /* As it is, we act as if this message never happened: - * whatever retrying was in place, remains in place. - */ - whack_log(RC_NOTIFICATION + md->note - , "%s: %s" - , enum_name(&state_names, (st == NULL)? STATE_MAIN_R0:st->st_state) - , enum_name(¬ification_names, md->note)); - - SEND_NOTIFICATION(md->note); - - DBG(DBG_CONTROL, - DBG_log("state transition function for %s failed: %s" - , enum_name(&state_names, from_state) - , enum_name(¬ification_names, md->note))); - break; - } -} diff --git a/src/pluto/demux.h b/src/pluto/demux.h deleted file mode 100644 index 6ce53c14f..000000000 --- a/src/pluto/demux.h +++ /dev/null @@ -1,97 +0,0 @@ -/* demultiplex incoming IKE messages - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _DEMUX_H -#define _DEMUX_H - -#include "packet.h" -#include "state.h" - -extern void init_demux(void); -extern bool send_packet(struct state *st, const char *where); -extern void comm_handle(const struct iface *ifp); - -extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE]; - -/* State transition function infrastructure - * - * com_handle parses a message, decides what state object it applies to, - * and calls the appropriate state transition function (STF). - * These declarations define the interface to these functions. - * - * Each STF must be able to be restarted up to any failure point: - * a later message will cause the state to be re-entered. This - * explains the use of the replace macro and the care in handling - * MP_INT members of struct state. - */ - -struct payload_digest { - pb_stream pbs; - union payload payload; - struct payload_digest *next; /* of same kind */ -}; - -/* message digest - * Note: raw_packet and packet_pbs are "owners" of space on heap. - */ - -struct msg_digest { - struct msg_digest *next; /* for free list */ - chunk_t raw_packet; /* if encrypted, received packet before decryption */ - const struct iface *iface; /* interface on which message arrived */ - ip_address sender; /* where message came from */ - u_int16_t sender_port; /* host order */ - pb_stream packet_pbs; /* whole packet */ - pb_stream message_pbs; /* message to be processed */ - struct isakmp_hdr hdr; /* message's header */ - bool encrypted; /* was it encrypted? */ - enum state_kind from_state; /* state we started in */ - const struct state_microcode *smc; /* microcode for initial state */ - struct state *st; /* current state object */ - pb_stream reply; /* room for reply */ - pb_stream rbody; /* room for reply body (after header) */ - notification_t note; /* reason for failure */ - bool dpd; /* peer supports RFC 3706 DPD */ - bool openpgp; /* peer supports OpenPGP certificates */ - bool ms_nt5; /* peer is a windows 2000+ host */ - -# define PAYLIMIT 40 - struct payload_digest - digest[PAYLIMIT], - *digest_roof, - *chain[ISAKMP_NEXT_ROOF]; - unsigned short nat_traversal_vid; -}; - -extern void release_md(struct msg_digest *md); - -/* status for state-transition-function - * Note: STF_FAIL + notification_t means fail with that notification - */ - -typedef enum { - STF_IGNORE, /* don't respond */ - STF_SUSPEND, /* unfinished -- don't release resources */ - STF_OK, /* success */ - STF_INTERNAL_ERROR, /* discard everything, we failed */ - STF_FAIL /* discard everything, something failed. notification_t added. */ -} stf_status; - -typedef stf_status state_transition_fn(struct msg_digest *md); - -extern void complete_state_transition(struct msg_digest **mdp, stf_status result); - -extern void free_md_pool(void); - -#endif /* _DEMUX_H */ diff --git a/src/pluto/dnskey.c b/src/pluto/dnskey.c deleted file mode 100644 index 91b1b6ac1..000000000 --- a/src/pluto/dnskey.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ??? for h_errno */ -#include - -#include - -#include -#include - -#include "constants.h" -#include "adns.h" /* needs */ -#include "defs.h" -#include "log.h" -#include "myid.h" -#include "connections.h" -#include "keys.h" /* needs connections.h */ -#include "dnskey.h" -#include "packet.h" -#include "timer.h" - -/* somebody has to decide */ -#define MAX_TXT_RDATA ((MAX_KEY_BYTES * 8 / 6) + 40) /* somewhat arbitrary overkill */ - -/* ADNS stuff */ - -int adns_qfd = NULL_FD, /* file descriptor for sending queries to adns (O_NONBLOCK) */ - adns_afd = NULL_FD; /* file descriptor for receiving answers from adns */ -static pid_t adns_pid = 0; -const char *pluto_adns_option = NULL; /* path from --pluto_adns */ - -int adns_restart_count; -#define ADNS_RESTART_MAX 20 - -void -init_adns(void) -{ - const char *adns_path = pluto_adns_option; - static const char adns_name[] = "_pluto_adns"; - const char *helper_bin_dir = getenv("IPSEC_LIBDIR"); - char adns_path_space[4096]; /* plenty long? */ - int qfds[2]; - int afds[2]; - - /* find a pathname to the ADNS program */ - if (adns_path == NULL) - { - /* pathname was not specified as an option: build it. - * First, figure out the directory to be used. - */ - ssize_t n; - - if (helper_bin_dir != NULL) - { - n = strlen(helper_bin_dir); - if ((size_t)n <= sizeof(adns_path_space) - sizeof(adns_name)) - { - strcpy(adns_path_space, helper_bin_dir); - if (n > 0 && adns_path_space[n -1] != '/') - { - adns_path_space[n++] = '/'; - } - } - } - else - { - /* The program will be in the same directory as Pluto, - * so we use the sympolic link /proc/self/exe to - * tell us of the path prefix. - */ - n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space)); - - if (n < 0) - { - exit_log_errno((e - , "readlink(\"/proc/self/exe\") failed in init_adns()")); - } - } - - if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name)) - { - exit_log("path to %s is too long", adns_name); - } - - while (n > 0 && adns_path_space[n - 1] != '/') - { - n--; - } - strcpy(adns_path_space + n, adns_name); - adns_path = adns_path_space; - } - if (access(adns_path, X_OK) < 0) - { - exit_log_errno((e, "%s missing or not executable", adns_path)); - } - - if (pipe(qfds) != 0 || pipe(afds) != 0) - { - exit_log_errno((e, "pipe(2) failed in init_adns()")); - } - - adns_pid = fork(); - switch (adns_pid) - { - case -1: - exit_log_errno((e, "fork() failed in init_adns()")); - - case 0: - /* child */ - { - /* Make stdin and stdout our pipes. - * Take care to handle case where pipes already use these fds. - */ - if (afds[1] == 0) - { - afds[1] = dup(afds[1]); /* avoid being overwritten */ - } - if (qfds[0] != 0) - { - dup2(qfds[0], 0); - close(qfds[0]); - } - if (afds[1] != 1) - { - dup2(afds[1], 1); - close(qfds[1]); - } - if (afds[0] > 1) - { - close(afds[0]); - } - if (afds[1] > 1) - { - close(afds[1]); - } - DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL)); - - execlp(adns_path, adns_name, NULL); - exit_log_errno((e, "execlp of %s failed", adns_path)); - } - default: - /* parent */ - close(qfds[0]); - adns_qfd = qfds[1]; - adns_afd = afds[0]; - close(afds[1]); - fcntl(adns_qfd, F_SETFD, FD_CLOEXEC); - fcntl(adns_afd, F_SETFD, FD_CLOEXEC); - fcntl(adns_qfd, F_SETFL, O_NONBLOCK); - break; - } -} - -void -stop_adns(void) -{ - close_any(adns_qfd); - adns_qfd = NULL_FD; - close_any(adns_afd); - adns_afd = NULL_FD; - - if (adns_pid != 0) - { - int status; - pid_t p = waitpid(adns_pid, &status, 0); - - if (p == -1) - { - log_errno((e, "waitpid for ADNS process failed")); - } - else if (WIFEXITED(status)) - { - if (WEXITSTATUS(status) != 0) - { - plog("ADNS process exited with status %d" - , (int) WEXITSTATUS(status)); - } - } - else if (WIFSIGNALED(status)) - { - plog("ADNS process terminated by signal %d", (int)WTERMSIG(status)); - } - else - { - plog("wait for end of ADNS process returned odd status 0x%x\n" - , status); - } - } -} - - - -/* tricky macro to pass any hot potato */ -#define TRY(x) { err_t ugh = x; if (ugh != NULL) return ugh; } - - -/* Process TXT X-IPsec-Server record, accumulating relevant ones - * in cr->gateways_from_dns, a list sorted by "preference". - * - * Format of TXT record body: X-IPsec-Server ( nnn ) = iii kkk - * nnn is a 16-bit unsigned integer preference - * iii is @FQDN or dotted-decimal IPv4 address or colon-hex IPv6 address - * kkk is an optional RSA public signing key in base 64. - * - * NOTE: we've got to be very wary of anything we find -- bad guys - * might have prepared it. - */ - -#define our_TXT_attr_string "X-IPsec-Server" -static const char our_TXT_attr[] = our_TXT_attr_string; - -identification_t* decode_iii(u_char **pp) -{ - identification_t *gw_id; - u_char *p = *pp + strspn(*pp, " \t"); - u_char *e = p + strcspn(p, " \t"); - u_char under = *e; - - if (p == e) - { - return NULL; - } - *e = '\0'; - gw_id = identification_create_from_string(p); - *e = under; - *pp = e + strspn(e, " \t"); - - return gw_id; -} - -static err_t process_txt_rr_body(u_char *str, bool doit, - enum dns_auth_level dns_auth_level, - struct adns_continuation *const cr) -{ - identification_t *client_id = cr->id; /* subject of query */ - u_char *p = str; - unsigned long pref = 0; - struct gw_info gi; - - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* is this for us? */ - if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0) - { - return NULL; /* neither interesting nor bad */ - } - - p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */ - p += strspn(p, " \t"); /* ignore leading whitespace */ - - /* decode '(' nnn ')' */ - if (*p != '(') - { - return "X-IPsec-Server missing '('"; - } - - { - char *e; - - p++; - pref = strtoul(p, &e, 0); - if ((u_char *)e == p) - { - return "malformed X-IPsec-Server priority"; - } - p = e + strspn(e, " \t"); - - if (*p != ')') - { - return "X-IPsec-Server priority missing ')'"; - } - p++; - p += strspn(p, " \t"); - - if (pref > 0xFFFF) - { - return "X-IPsec-Server priority larger than 0xFFFF"; - } - } - - /* time for '=' */ - - if (*p != '=') - { - return "X-IPsec-Server priority missing '='"; - } - p++; - p += strspn(p, " \t"); - - /* Decode iii (Security Gateway ID). */ - zero(&gi); /* before first use */ - - gi.gw_id = decode_iii(&p); - if (gi.gw_id == NULL) - { - return "TXT " our_TXT_attr_string " badly formed (no gateway specified)"; - } - - if (!cr->sgw_specified) - { - /* we don't know the peer's ID (because we are initiating - * and we don't know who to initiate with. - * So we're looking for gateway specs with an IP address - */ - if (gi.gw_id->get_type(gi.gw_id) != ID_IPV4_ADDR && - gi.gw_id->get_type(gi.gw_id) != ID_IPV6_ADDR) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored because gateway's IP is unspecified", - our_TXT_attr, client_id, gi.gw_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - else - { - /* We do know the peer's ID (because we are responding) - * So we're looking for gateway specs specifying this known ID. - */ - identification_t *peer_id = cr->sgw_id; - - if (!peer_id->equals(peer_id, gi.gw_id)) - { - DBG(DBG_DNS, - DBG_log("TXT %s record for '%Y': security gateway '%Y';" - " ignored -- looking to confirm '%Y' as gateway", - our_TXT_attr, client_id, gi.gw_id, peer_id); - ) - return NULL; /* we cannot use this record, but it isn't wrong */ - } - } - - if (doit) - { - /* really accept gateway */ - struct gw_info **gwip; /* gateway insertion point */ - - gi.client_id = client_id; /* will need to unshare_id_content */ - - /* decode optional kkk: base 64 encoding of key */ - - gi.gw_key_present = *p != '\0'; - if (gi.gw_key_present) - { - /* Decode base 64 encoding of key. - * Similar code is in process_lwdnsq_key. - */ - u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */ - size_t sz; - err_t ugh; - chunk_t rfc3110_chunk; - public_key_t *key; - - ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - return builddiag("malformed key data: %s", ugh); - } - if (sz > sizeof(buf)) - { - return builddiag("key data larger than %lu bytes", - (unsigned long) sizeof(buf)); - } - rfc3110_chunk = chunk_create(buf, sz); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_chunk, - BUILD_END); - if (key == NULL) - { - return builddiag("invalid key data"); - } - - /* now find a key entry to put it in */ - gi.key = public_key_from_rsa(key); - - unreference_key(&cr->last_info); - cr->last_info = reference_key(gi.key); - } - - /* we're home free! Allocate everything and add to gateways list. */ - gi.refcnt = 1; - gi.pref = pref; - gi.key->dns_auth_level = dns_auth_level; - gi.key->last_tried_time = gi.key->last_worked_time = NO_TIME; - - /* find insertion point */ - for (gwip = &cr->gateways_from_dns; *gwip != NULL && (*gwip)->pref < pref; gwip = &(*gwip)->next) - ; - - DBG(DBG_DNS, - { - chunk_t keyid; - public_key_t *key = gi.key->public_key; - - if (gi.gw_key_present && - key->get_fingerprint(key, KEYID_PUBKEY_SHA1, &keyid)) - { - DBG_log("gateway for %s is %s with key %#B", - client_id, gi.gw_id, &keyid); - } - else - { - DBG_log("gateway for '%Y' is '%Y'; no key specified", - client_id, gi.gw_id); - } - }); - - gi.next = *gwip; - *gwip = clone_thing(gi); - (*gwip)->gw_id = (*gwip)->gw_id->clone((*gwip)->gw_id); - (*gwip)->client_id = (*gwip)->client_id->clone((*gwip)->client_id); - } - - return NULL; -} - -static const char * -rr_typename(int type) -{ - switch (type) - { - case T_TXT: - return "TXT"; - case T_KEY: - return "KEY"; - default: - return "???"; - } -} - - -/* structure of Query Reply (RFC 1035 4.1.1): - * - * +---------------------+ - * | Header | - * +---------------------+ - * | Question | the question for the name server - * +---------------------+ - * | Answer | RRs answering the question - * +---------------------+ - * | Authority | RRs pointing toward an authority - * +---------------------+ - * | Additional | RRs holding additional information - * +---------------------+ - */ - -/* Header section format (as modified by RFC 2535 6.1): - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ID | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QDCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ANCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | NSCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | ARCOUNT | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ -struct qr_header { - u_int16_t id; /* 16-bit identifier to match query */ - - u_int16_t stuff; /* packed crud: */ - -#define QRS_QR 0x8000 /* QR: on if this is a response */ - -#define QRS_OPCODE_SHIFT 11 /* OPCODE field */ -#define QRS_OPCODE_MASK 0xF -#define QRSO_QUERY 0 /* standard query */ -#define QRSO_IQUERY 1 /* inverse query */ -#define QRSO_STATUS 2 /* server status request query */ - -#define QRS_AA 0x0400 /* AA: on if Authoritative Answer */ -#define QRS_TC 0x0200 /* TC: on if truncation happened */ -#define QRS_RD 0x0100 /* RD: on if recursion desired */ -#define QRS_RA 0x0080 /* RA: on if recursion available */ -#define QRS_Z 0x0040 /* Z: reserved; must be zero */ -#define QRS_AD 0x0020 /* AD: on if authentic data (RFC 2535) */ -#define QRS_CD 0x0010 /* AD: on if checking disabled (RFC 2535) */ - -#define QRS_RCODE_SHIFT 0 /* RCODE field: response code */ -#define QRS_RCODE_MASK 0xF -#define QRSR_OK 0 - - - u_int16_t qdcount; /* number of entries in question section */ - u_int16_t ancount; /* number of resource records in answer section */ - u_int16_t nscount; /* number of name server resource records in authority section */ - u_int16_t arcount; /* number of resource records in additional records section */ -}; - -static field_desc qr_header_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "ID", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "stuff", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "QD Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Answer Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Authority Count", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Additional Count", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qr_header_desc = { - "Query Response Header", - qr_header_fields, - sizeof(struct qr_header) -}; - -/* Messages for codes in RCODE (see RFC 1035 4.1.1) */ -static const err_t rcode_text[QRS_RCODE_MASK + 1] = { - NULL, /* not an error */ - "Format error - The name server was unable to interpret the query", - "Server failure - The name server was unable to process this query" - " due to a problem with the name server", - "Name Error - Meaningful only for responses from an authoritative name" - " server, this code signifies that the domain name referenced in" - " the query does not exist", - "Not Implemented - The name server does not support the requested" - " kind of query", - "Refused - The name server refuses to perform the specified operation" - " for policy reasons", - /* the rest are reserved for future use */ - }; - -/* throw away a possibly compressed domain name */ - -static err_t -eat_name(pb_stream *pbs) -{ - u_char name_buf[NS_MAXDNAME + 2]; - u_char *ip = pbs->cur; - unsigned oi = 0; - unsigned jump_count = 0; - - for (;;) - { - u_int8_t b; - - if (ip >= pbs->roof) - return "ran out of message while skipping domain name"; - - b = *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (b == 0) - break; - - switch (b & 0xC0) - { - case 0x00: - /* we grab the next b characters */ - if (oi + b > NS_MAXDNAME) - return "domain name too long"; - - if (pbs->roof - ip <= b) - return "domain name falls off end of message"; - - if (oi != 0) - name_buf[oi++] = '.'; - - memcpy(name_buf + oi, ip, b); - oi += b; - ip += b; - if (jump_count == 0) - pbs->cur = ip; - break; - - case 0xC0: - { - unsigned ix; - - if (ip >= pbs->roof) - return "ran out of message in middle of compressed domain name"; - - ix = ((b & ~0xC0u) << 8) | *ip++; - if (jump_count == 0) - pbs->cur = ip; - - if (ix >= pbs_room(pbs)) - return "impossible compressed domain name"; - - /* Avoid infinite loop. - * There can be no more jumps than there are bytes - * in the packet. Not a tight limit, but good enough. - */ - jump_count++; - if (jump_count > pbs_room(pbs)) - return "loop in compressed domain name"; - - ip = pbs->start + ix; - } - break; - - default: - return "invalid code in label"; - } - } - - name_buf[oi++] = '\0'; - - DBG(DBG_DNS, DBG_log("skipping name %s", name_buf)); - - return NULL; -} - -static err_t -eat_name_helpfully(pb_stream *pbs, const char *context) -{ - err_t ugh = eat_name(pbs); - - return ugh == NULL? ugh - : builddiag("malformed name within DNS record of %s: %s", context, ugh); -} - -/* non-variable part of 4.1.2 Question Section entry: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct qs_fixed { - u_int16_t qtype; - u_int16_t qclass; -}; - -static field_desc qs_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "QTYPE", &rr_qtype_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "QCLASS", &rr_class_names }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc qs_fixed_desc = { - "Question Section entry fixed part", - qs_fixed_fields, - sizeof(struct qs_fixed) -}; - -/* 4.1.3. Resource record format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / / - * / NAME / - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | CLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | TTL | - * | | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | RDLENGTH | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| - * / RDATA / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - -struct rr_fixed { - u_int16_t type; - u_int16_t class; - u_int32_t ttl; /* actually signed */ - u_int16_t rdlength; -}; - - -static field_desc rr_fixed_fields[] = { - { ft_loose_enum, 16/BITS_PER_BYTE, "type", &rr_type_names }, - { ft_loose_enum, 16/BITS_PER_BYTE, "class", &rr_class_names }, - { ft_nat, 32/BITS_PER_BYTE, "TTL", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "RD length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc rr_fixed_desc = { - "Resource Record fixed part", - rr_fixed_fields, - /* note: following is tricky: avoids padding problems */ - offsetof(struct rr_fixed, rdlength) + sizeof(u_int16_t) -}; - -/* RFC 1035 3.3.14: TXT RRs have text in the RDATA field. - * It is in the form of a sequence of s as described in 3.3. - * unpack_txt_rdata() deals with this peculiar representation. - */ - -/* RFC 2535 3.1 KEY RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | flags | protocol | algorithm | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | / - * / public key / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| - */ - -struct key_rdata { - u_int16_t flags; - u_int8_t protocol; - u_int8_t algorithm; -}; - -static field_desc key_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "flags", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "protocol", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL }, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc key_rdata_desc = { - "KEY RR RData fixed part", - key_rdata_fields, - sizeof(struct key_rdata) -}; - -/* RFC 2535 4.1 SIG RDATA format: - * - * 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | type covered | algorithm | labels | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | original TTL | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature expiration | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | signature inception | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | key tag | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ signer's name + - * | / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-/ - * / / - * / signature / - * / / - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -struct sig_rdata { - u_int16_t type_covered; - u_int8_t algorithm; - u_int8_t labels; - u_int32_t original_ttl; - u_int32_t sig_expiration; - u_int32_t sig_inception; - u_int16_t key_tag; -}; - -static field_desc sig_rdata_fields[] = { - { ft_nat, 16/BITS_PER_BYTE, "type_covered", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "algorithm", NULL}, - { ft_nat, 8/BITS_PER_BYTE, "labels", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "original ttl", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig expiration", NULL}, - { ft_nat, 32/BITS_PER_BYTE, "sig inception", NULL}, - { ft_nat, 16/BITS_PER_BYTE, "key tag", NULL}, - { ft_end, 0, NULL, NULL } -}; - -static struct_desc sig_rdata_desc = { - "SIG RR RData fixed part", - sig_rdata_fields, - sizeof(struct sig_rdata) -}; - -/* handle a KEY Resource Record. */ - -#ifdef USE_KEYRR -static err_t -process_key_rr(u_char *ptr, size_t len -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - pb_stream pbs; - struct key_rdata kr; - - if (len < sizeof(struct key_rdata)) - return "KEY Resource Record's RD Length is too small"; - - init_pbs(&pbs, ptr, len, "KEY RR"); - - if (!in_struct(&kr, &key_rdata_desc, &pbs, NULL)) - return "failed to get fixed part of KEY Resource Record RDATA"; - - if (kr.protocol == 4 /* IPSEC (RFC 2535 3.1.3) */ - && kr.algorithm == 1 /* RSA/MD5 (RFC 2535 3.2) */ - && (kr.flags & 0x8000) == 0 /* use for authentication (3.1.2) */ - && (kr.flags & 0x2CF0) == 0) /* must be zero */ - { - /* we have what seems to be a tasty key */ - - if (doit) - { - chunk_t k = { pbs.cur, pbs_left(&pbs) }; - - TRY(add_public_key(&cr->id, dns_auth_level, PUBKEY_ALG_RSA, &k - , &cr->keys_from_dns)); - } - } - return NULL; -} -#endif /* USE_KEYRR */ - - -/* unpack TXT rr RDATA into C string. - * A sequence of s as described in RFC 1035 3.3. - * We concatenate them. - */ -static err_t -unpack_txt_rdata(u_char *d, size_t dlen, const u_char *s, size_t slen) -{ - size_t i = 0 - , o = 0; - - while (i < slen) - { - size_t cl = s[i++]; - - if (i + cl > slen) - return "TXT rr RDATA representation malformed"; - - if (o + cl >= dlen) - return "TXT rr RDATA too large"; - - memcpy(d + o, s + i, cl); - i += cl; - o += cl; - } - d[o] = '\0'; - if (strlen(d) != o) - return "TXT rr RDATA contains a NUL"; - - return NULL; -} - -static err_t -process_txt_rr(u_char *rdata, size_t rdlen -, bool doit /* should we capture information? */ -, enum dns_auth_level dns_auth_level -, struct adns_continuation *const cr) -{ - u_char str[RSA_MAX_ENCODING_BYTES * 8 / 6 + 20]; /* space for unpacked RDATA */ - - TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen)); - return process_txt_rr_body(str, doit, dns_auth_level, cr); -} - -static err_t -process_answer_section(pb_stream *pbs -, bool doit /* should we capture information? */ -, enum dns_auth_level *dns_auth_level -, u_int16_t ancount /* number of RRs in the answer section */ -, struct adns_continuation *const cr) -{ - const int type = cr->query.type; /* type of RR of interest */ - unsigned c; - - DBG(DBG_DNS, DBG_log("*Answer Section:")); - - for (c = 0; c != ancount; c++) - { - struct rr_fixed rrf; - size_t tail; - - /* ??? do we need to match the name? */ - - TRY(eat_name_helpfully(pbs, "Answer Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL)) - return "failed to get fixed part of Answer Section Resource Record"; - - if (rrf.rdlength > pbs_left(pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - if (rrf.type == type && rrf.class == C_IN) - { - err_t ugh = NULL; - - switch (type) - { -#ifdef USE_KEYRR - case T_KEY: - ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; -#endif /* USE_KEYRR */ - case T_TXT: - ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr); - break; - case T_SIG: - /* Check if SIG RR authenticates what we are learning. - * The RRset covered by a SIG must have the same owner, - * class, and type. - * For us, the class is always C_IN, so that matches. - * We decode the SIG RR's fixed part to check - * that the type_covered field matches our query type - * (this may be redundant). - * We don't check the owner (apparently this is the - * name on the record) -- we assume that it matches - * or we would not have been given this SIG in the - * Answer Section. - * - * We only look on first pass, and only if we've something - * to learn. This cuts down on useless decoding. - */ - if (!doit && *dns_auth_level == DAL_UNSIGNED) - { - struct sig_rdata sr; - - if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL)) - ugh = "failed to get fixed part of SIG Resource Record RDATA"; - else if (sr.type_covered == type) - *dns_auth_level = DAL_SIGNED; - } - break; - default: - ugh = builddiag("unexpected RR type %d", type); - break; - } - if (ugh != NULL) - return ugh; - } - in_raw(NULL, tail, pbs, "RR RDATA"); - } - - return doit - && cr->gateways_from_dns == NULL -#ifdef USE_KEYRR - && cr->keys_from_dns == NULL -#endif /* USE_KEYRR */ - ? builddiag("no suitable %s record found in DNS", rr_typename(type)) - : NULL; -} - -/* process DNS answer -- TXT or KEY query */ - -static err_t -process_dns_answer(struct adns_continuation *const cr -, u_char ans[], int anslen) -{ - const int type = cr->query.type; /* type of record being sought */ - int r; /* all-purpose return value holder */ - u_int16_t c; /* number of current RR in current answer section */ - pb_stream pbs; - u_int8_t *ans_start; /* saved position of answer section */ - struct qr_header qr_header; - enum dns_auth_level dns_auth_level; - - init_pbs(&pbs, ans, anslen, "Query Response Message"); - - /* decode and check header */ - - if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL)) - return "malformed header"; - - /* ID: nothing to do with us */ - - /* stuff -- lots of things */ - if ((qr_header.stuff & QRS_QR) == 0) - return "not a response?!?"; - - if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY) - return "unexpected opcode"; - - /* I don't think we care about AA */ - - if (qr_header.stuff & QRS_TC) - return "response truncated"; - - /* I don't think we care about RD, RA, or CD */ - - /* AD means "authentic data" */ - dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC; - - if (qr_header.stuff & QRS_Z) - return "Z bit is not zero"; - - r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK; - if (r != 0) - return r < (int)countof(rcode_text)? rcode_text[r] : "unknown rcode"; - - if (qr_header.ancount == 0) - return builddiag("no %s RR found by DNS", rr_typename(type)); - - /* end of header checking */ - - /* Question Section processing */ - - /* 4.1.2. Question section format: - * 1 1 1 1 1 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | | - * / QNAME / - * / / - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QTYPE | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - * | QCLASS | - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - - DBG(DBG_DNS, DBG_log("*Question Section:")); - - for (c = 0; c != qr_header.qdcount; c++) - { - struct qs_fixed qsf; - - TRY(eat_name_helpfully(&pbs, "Question Section")); - - if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Question Section"; - - if (qsf.qtype != type) - return "unexpected QTYPE in Question Section"; - - if (qsf.qclass != C_IN) - return "unexpected QCLASS in Question Section"; - } - - /* rest of sections are made up of Resource Records */ - - /* Answer Section processing -- error checking, noting T_SIG */ - - ans_start = pbs.cur; /* remember start of answer section */ - - TRY(process_answer_section(&pbs, FALSE, &dns_auth_level - , qr_header.ancount, cr)); - - /* Authority Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Authority Section:")); - - for (c = 0; c != qr_header.nscount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Authority Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Authority Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* Additional Section processing (just sanity checking) */ - - DBG(DBG_DNS, DBG_log("*Additional Section:")); - - for (c = 0; c != qr_header.arcount; c++) - { - struct rr_fixed rrf; - size_t tail; - - TRY(eat_name_helpfully(&pbs, "Additional Section")); - - if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL)) - return "failed to get fixed part of Additional Section Resource Record"; - - if (rrf.rdlength > pbs_left(&pbs)) - return "RD Length extends beyond end of message"; - - /* ??? should we care about ttl? */ - - tail = rrf.rdlength; - - in_raw(NULL, tail, &pbs, "RR RDATA"); - } - - /* done all sections */ - - /* ??? is padding legal, or can we complain if more left in record? */ - - /* process Answer Section again -- accept contents */ - - pbs.cur = ans_start; /* go back to start of answer section */ - - return process_answer_section(&pbs, TRUE, &dns_auth_level - , qr_header.ancount, cr); -} - -/****************************************************************/ - -static err_t build_dns_name(u_char name_buf[NS_MAXDNAME + 2], - unsigned long serial USED_BY_DEBUG, - identification_t *id, - const char *typename USED_BY_DEBUG, - identification_t *gw USED_BY_DEBUG) -{ - /* note: all end in "." to suppress relative searches */ - id = resolve_myid(id); - - switch (id->get_type(id)) - { - case ID_IPV4_ADDR: - { - chunk_t b = id->get_encoding(id); - - snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa.", - b.ptr[3], b.ptr[2], b.ptr[1], b.ptr[0]); - break; - } - case ID_IPV6_ADDR: - { - chunk_t b = id->get_encoding(id); - size_t bl; - u_char *op = name_buf; - static const char suffix[] = "IP6.INT."; - - for (bl = b.len; bl-- != 0; ) - { - if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1) - { - return "IPv6 reverse name too long"; - } - op += sprintf(op, "%x.%x.", b.ptr[bl] & 0xF, b.ptr[bl] >> 4); - } - strcpy(op, suffix); - break; - } - case ID_FQDN: - { - if (snprintf(name_buf, NS_MAXDNAME + 2, "%Y.", id) > NS_MAXDNAME + 1) - { - return "FQDN too long for domain name"; - } - break; - } - default: - return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR"; - } - - DBG(DBG_CONTROL | DBG_DNS, - DBG_log("DNS query %lu for %s for %s (gw: %Y)", serial, typename, name_buf, gw) - ) - return NULL; -} - -void gw_addref(struct gw_info *gw) -{ - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt)) - gw->refcnt++; - } -} - -void gw_delref(struct gw_info **gwp) -{ - struct gw_info *gw = *gwp; - - if (gw != NULL) - { - DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt)); - - passert(gw->refcnt != 0); - gw->refcnt--; - if (gw->refcnt == 0) - { - DESTROY_IF(gw->client_id); - DESTROY_IF(gw->gw_id); - if (gw->gw_key_present) - { - unreference_key(&gw->key); - } - gw_delref(&gw->next); - free(gw); /* trickery could make this a tail-call */ - } - *gwp = NULL; - } -} - -static int adns_in_flight = 0; /* queries outstanding */ - -/* Start an asynchronous DNS query. - * - * For KEY record, the result will be a list in cr->keys_from_dns. - * For TXT records, the result will be a list in cr->gateways_from_dns. - * - * If sgw_id is null, only consider TXT records that specify an - * IP address for the gatway: we need this in the initiation case. - * - * If sgw_id is non-null, only consider TXT records that specify - * this id as the security gatway; this is useful to the Responder - * for confirming claims of gateways. - * - * Continuation cr gives information for continuing when the result shows up. - * - * Two kinds of errors must be handled: synchronous (immediate) - * and asynchronous. Synchronous errors are indicated by the returned - * value of start_adns_query; in this case, the continuation will - * have been freed and the continuation routine will not be called. - * Asynchronous errors are indicated by the ugh parameter passed to the - * continuation routine. - * - * After the continuation routine has completed, handle_adns_answer - * will free the continuation. The continuation routine should have - * freed any axiliary resources. - * - * Note: in the synchronous error case, start_adns_query will have - * freed the continuation; this means that the caller will have to - * be very careful to release any auxiliary resources that were in - * the continuation record without using the continuation record. - * - * Either there will be an error result passed to the continuation routine, - * or the results will be in cr->keys_from_dns or cr->gateways_from_dns. - * The result variables must by left NULL by the continutation routine. - * The continuation routine is responsible for establishing and - * disestablishing any logging context (whack_log_fd, cur_*). - */ - -static struct adns_continuation *continuations = NULL; /* newest of queue */ -static struct adns_continuation *next_query = NULL; /* oldest not sent */ - -static struct adns_continuation *continuation_for_qtid(unsigned long qtid) -{ - struct adns_continuation *cr = NULL; - - if (qtid != 0) - { - for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous) - ; - } - return cr; -} - -static void release_adns_continuation(struct adns_continuation *cr) -{ - passert(cr != next_query); - gw_delref(&cr->gateways_from_dns); -#ifdef USE_KEYRR - free_public_keys(&cr->keys_from_dns); -#endif /* USE_KEYRR */ - cr->id = cr->id->clone(cr->id); - cr->sgw_id = cr->sgw_id->clone(cr->sgw_id); - - /* unlink from doubly-linked list */ - if (cr->next == NULL) - { - continuations = cr->previous; - } - else - { - cr->next->previous = cr->previous; - } - - if (cr->previous != NULL) - { - cr->previous->next = cr->next; - } - - free(cr); -} - -err_t start_adns_query(identification_t *id, /* domain to query */ - identification_t *sgw_id, /* if non-null, any accepted gw_info must match */ - int type, /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn, - struct adns_continuation *cr) -{ - static unsigned long qtid = 1; /* query transaction id; NOTE: static */ - const char *typename = rr_typename(type); - - if(adns_pid == 0 && adns_restart_count < ADNS_RESTART_MAX) - { - plog("ADNS helper was not running. Restarting attempt %d",adns_restart_count); - init_adns(); - } - - /* Splice this in at head of doubly-linked list of continuations. - * Note: this must be done before any release_adns_continuation(). - */ - cr->next = NULL; - cr->previous = continuations; - if (continuations != NULL) - { - continuations->next = cr; - } - continuations = cr; - - cr->qtid = qtid++; - cr->type = type; - cr->cont_fn = cont_fn; - cr->id = id->clone(id); - cr->sgw_specified = (sgw_id != NULL); - cr->sgw_id = cr->sgw_specified ? - sgw_id->clone(sgw_id) : - identification_create_from_string("%any"); - cr->gateways_from_dns = NULL; -#ifdef USE_KEYRR - cr->keys_from_dns = NULL; -#endif /* USE_KEYRR */ - -#ifdef DEBUG - cr->debugging = cur_debugging; -#else - cr->debugging = LEMPTY; -#endif - - zero(&cr->query); - { - err_t ugh = build_dns_name(cr->query.name_buf, cr->qtid, id, - typename, cr->sgw_id); - - if (ugh) - { - release_adns_continuation(cr); - return ugh; - } - } - - if (next_query == NULL) - next_query = cr; - - unsent_ADNS_queries = TRUE; - - return NULL; -} - -/* send remaining ADNS queries (until pipe full or none left) - * - * This is a co-routine, so it uses static variables to - * preserve state across calls. - */ -bool unsent_ADNS_queries = FALSE; - -void -send_unsent_ADNS_queries(void) -{ - static const unsigned char *buf_end = NULL; /* NOTE STATIC */ - static const unsigned char *buf_cur = NULL; /* NOTE STATIC */ - - if (adns_qfd == NULL_FD) - return; /* nothing useful to do */ - - for (;;) - { - if (buf_cur != buf_end) - { - static int try = 0; /* NOTE STATIC */ - size_t n = buf_end - buf_cur; - ssize_t r = write(adns_qfd, buf_cur, n); - - if (r == -1) - { - switch (errno) - { - case EINTR: - continue; /* try again now */ - case EAGAIN: - DBG(DBG_DNS, DBG_log("EAGAIN writing to ADNS")); - break; /* try again later */ - default: - try++; - log_errno((e, "error %d writing DNS query", try)); - break; /* try again later */ - } - unsent_ADNS_queries = TRUE; - break; /* done! */ - } - else - { - passert(r >= 0); - try = 0; - buf_cur += r; - } - } - else - { - if (next_query == NULL) - { - unsent_ADNS_queries = FALSE; - break; /* done! */ - } - - next_query->query.debugging = next_query->debugging; - next_query->query.serial = next_query->qtid; - next_query->query.len = sizeof(next_query->query); - next_query->query.qmagic = ADNS_Q_MAGIC; - next_query->query.type = next_query->type; - buf_cur = (const void *)&next_query->query; - buf_end = buf_cur + sizeof(next_query->query); - - next_query = next_query->next; - adns_in_flight++; - } - } -} - -static void recover_adns_die(void) -{ - struct adns_continuation *cr = NULL; - - adns_pid = 0; - if(adns_restart_count < ADNS_RESTART_MAX) { - adns_restart_count++; - - /* next DNS query will restart it */ - - /* we have to walk the list of the outstanding requests, - * and redo them! - */ - - cr = continuations; - - /* find the head of the list */ - if(continuations != NULL) { - for (; cr->previous != NULL; cr = cr->previous); - } - - next_query = cr; - - if(next_query != NULL) { - unsent_ADNS_queries = TRUE; - } - } -} - -void reset_adns_restart_count(void) -{ - adns_restart_count=0; -} - -void handle_adns_answer(void) -{ - /* These are retained across calls to handle_adns_answer. */ - static size_t buflen = 0; /* bytes in answer buffer */ - static struct adns_answer buf; - - ssize_t n; - - passert(buflen < sizeof(buf)); - n = read(adns_afd, (unsigned char *)&buf + buflen, sizeof(buf) - buflen); - - if (n < 0) - { - if (errno != EINTR) - { - log_errno((e, "error reading answer from adns")); - /* ??? how can we recover? */ - } - n = 0; /* now n reflects amount read */ - } - else if (n == 0) - { - /* EOF */ - if (adns_in_flight != 0) - { - plog("EOF from ADNS with %d queries outstanding (restarts %d)" - , adns_in_flight, adns_restart_count); - recover_adns_die(); - } - if (buflen != 0) - { - plog("EOF from ADNS with %lu bytes of a partial answer outstanding" - "(restarts %d)" - , (unsigned long)buflen - , adns_restart_count); - recover_adns_die(); - } - stop_adns(); - return; - } - else - { - passert(adns_in_flight > 0); - } - - buflen += n; - while (buflen >= offsetof(struct adns_answer, ans) && buflen >= buf.len) - { - /* we've got a tasty answer -- process it */ - err_t ugh; - struct adns_continuation *cr = continuation_for_qtid(buf.serial); /* assume it works */ - const char *typename = rr_typename(cr->query.type); - const char *name_buf = cr->query.name_buf; - -#ifdef USE_KEYRR - passert(cr->keys_from_dns == NULL); -#endif /* USE_KEYRR */ - passert(cr->gateways_from_dns == NULL); - adns_in_flight--; - if (buf.result == -1) - { - /* newer resolvers support statp->res_h_errno as well as h_errno. - * That might be better, but older resolvers don't. - * See resolver(3), if you have it. - * The undocumented(!) h_errno values are defined in - * /usr/include/netdb.h. - */ - switch (buf.h_errno_val) - { - case NO_DATA: - ugh = builddiag("no %s record for %s", typename, name_buf); - break; - case HOST_NOT_FOUND: - ugh = builddiag("no host %s for %s record", name_buf, typename); - break; - default: - ugh = builddiag("failure querying DNS for %s of %s: %s" - , typename, name_buf, hstrerror(buf.h_errno_val)); - break; - } - } - else if (buf.result > (int) sizeof(buf.ans)) - { - ugh = builddiag("(INTERNAL ERROR) answer too long (%ld) for buffer" - , (long)buf.result); - } - else - { - ugh = process_dns_answer(cr, buf.ans, buf.result); - if (ugh != NULL) - ugh = builddiag("failure processing %s record of DNS answer for %s: %s" - , typename, name_buf, ugh); - } - DBG(DBG_RAW | DBG_CRYPT | DBG_PARSING | DBG_CONTROL | DBG_DNS, - DBG_log(BLANK_FORMAT); - if (ugh == NULL) - DBG_log("asynch DNS answer %lu for %s of %s" - , cr->query.serial, typename, name_buf); - else - DBG_log("asynch DNS answer %lu %s", cr->query.serial, ugh); - ); - - passert(GLOBALS_ARE_RESET()); - cr->cont_fn(cr, ugh); - reset_globals(); - release_adns_continuation(cr); - - /* shift out answer that we've consumed */ - buflen -= buf.len; - memmove((unsigned char *)&buf, (unsigned char *)&buf + buf.len, buflen); - } -} diff --git a/src/pluto/dnskey.h b/src/pluto/dnskey.h deleted file mode 100644 index 39a406cbd..000000000 --- a/src/pluto/dnskey.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Find public key in DNS - * Copyright (C) 2000-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -extern int adns_qfd; /* file descriptor for sending queries to adns */ -extern int adns_afd; /* file descriptor for receiving answers from adns */ -extern const char *pluto_adns_option; /* path from --pluto_adns */ -extern void init_adns(void); -extern void stop_adns(void); -extern void handle_adns_answer(void); - -extern bool unsent_ADNS_queries; -extern void send_unsent_ADNS_queries(void); - -/* (common prefix of) stuff remembered between async query and answer. - * Filled in by start_adns_query. - * Freed by call to release_adns_continuation. - */ - -struct adns_continuation; /* forward declaration (not far!) */ - -typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh); - -struct adns_continuation { - unsigned long qtid; /* query transaction id number */ - int type; /* T_TXT or T_KEY, selecting rr type of interest */ - cont_fn_t cont_fn; /* function to carry on suspended work */ - identification_t *id; /* subject of query */ - bool sgw_specified; - identification_t *sgw_id; /* peer, if constrained */ - lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ - struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */ -#ifdef USE_KEYRR - struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */ -#endif - struct adns_continuation *previous, *next; - struct pubkey *last_info; /* the last structure we accumulated */ - struct adns_query query; -}; - -extern err_t start_adns_query(identification_t *id /* domain to query */ - , identification_t *sgw_id /* if non-null, any accepted gw_info must match */ - , int type /* T_TXT or T_KEY, selecting rr type of interest */ - , cont_fn_t cont_fn /* continuation function */ - , struct adns_continuation *cr); - - -/* Gateway info gleaned from reverse DNS of client */ -struct gw_info { - unsigned refcnt; /* reference counted! */ - unsigned pref; /* preference: lower is better */ -#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */ - identification_t* client_id; /* id of client of peer */ - identification_t* gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */ - bool gw_key_present; - struct pubkey *key; - struct gw_info *next; -}; - -extern void gw_addref(struct gw_info *gw); -extern void gw_delref(struct gw_info **gwp); -extern void reset_adns_restart_count(void); - diff --git a/src/pluto/event_queue.c b/src/pluto/event_queue.c deleted file mode 100644 index 602a013ee..000000000 --- a/src/pluto/event_queue.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include "event_queue.h" - -#include -#include -#include - -typedef struct private_event_queue_t private_event_queue_t; - -/** - * Private data of event_queue_t class. - */ -struct private_event_queue_t { - /** - * Public event_queue_t interface. - */ - event_queue_t public; - - /** - * List of queued events (event_t*). - */ - linked_list_t *events; - - /** - * Mutex for event list. - */ - mutex_t *mutex; - - /** - * Read end of the notification pipe. - */ - int read_fd; - - /** - * Write end of the notification pipe. - */ - int write_fd; - -}; - -typedef struct event_t event_t; - -struct event_t { - /** - * Callback function. - */ - void (*callback)(void *data); - - /** - * Data to supply to the callback. - */ - void *data; - - /** - * Cleanup function. - */ - void (*cleanup)(void *data); -}; - -static event_t *event_create(void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *this; - INIT(this, - .callback = callback, - .data = data, - .cleanup = cleanup, - ); - return this; -} - -static void event_destroy(event_t *this) -{ - if (this->cleanup) - { - this->cleanup(this->data); - } - free(this); -} - -METHOD(event_queue_t, get_event_fd, int, - private_event_queue_t *this) -{ - return this->read_fd; -} - -METHOD(event_queue_t, handle, void, - private_event_queue_t *this) -{ - char buf[10]; - linked_list_t *events; - event_t *event; - this->mutex->lock(this->mutex); - /* flush pipe */ - while (read(this->read_fd, &buf, sizeof(buf)) == sizeof(buf)); - /* replace the list, so we can unlock the mutex while executing the jobs */ - events = this->events; - this->events = linked_list_create(); - this->mutex->unlock(this->mutex); - - while (events->remove_first(events, (void**)&event) == SUCCESS) - { - event->callback(event->data); - event_destroy(event); - } - events->destroy(events); -} - -METHOD(event_queue_t, queue, void, - private_event_queue_t *this, void (*callback)(void *data), void *data, - void (*cleanup)(void *data)) -{ - event_t *event = event_create(callback, data, cleanup); - char c = 0; - this->mutex->lock(this->mutex); - this->events->insert_last(this->events, event); - ignore_result(write(this->write_fd, &c, 1)); - this->mutex->unlock(this->mutex); -} - -METHOD(event_queue_t, destroy, void, - private_event_queue_t *this) -{ - this->mutex->lock(this->mutex); - this->events->destroy_function(this->events, (void*)event_destroy); - this->mutex->unlock(this->mutex); - this->mutex->destroy(this->mutex); - close(this->read_fd); - close(this->write_fd); - free(this); -} - -static bool set_nonblock(int socket) -{ - int flags = fcntl(socket, F_GETFL); - return flags != -1 && fcntl(socket, F_SETFL, flags | O_NONBLOCK) != -1; -} - -static bool set_cloexec(int socket) -{ - int flags = fcntl(socket, F_GETFD); - return flags != -1 && fcntl(socket, F_SETFD, flags | FD_CLOEXEC) != -1; -} - -/* - * Described in header. - */ -event_queue_t *event_queue_create() -{ - private_event_queue_t *this; - int fd[2]; - - INIT(this, - .public = { - .get_event_fd = _get_event_fd, - .handle = _handle, - .queue = _queue, - .destroy = _destroy, - }, - .events = linked_list_create(), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - ); - - if (pipe(fd) == -1 || - !set_nonblock(fd[0]) || !set_cloexec(fd[0]) || - !set_nonblock(fd[1]) || !set_cloexec(fd[1])) - { - DBG1(DBG_JOB, "failed to create pipe for job queue"); - _destroy(this); - return NULL; - } - - this->read_fd = fd[0]; - this->write_fd = fd[1]; - - return &this->public; -} - diff --git a/src/pluto/event_queue.h b/src/pluto/event_queue.h deleted file mode 100644 index 343729e25..000000000 --- a/src/pluto/event_queue.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup event_queue event_queue - * @{ @ingroup pluto - */ - -#ifndef EVENT_QUEUE_H_ -#define EVENT_QUEUE_H_ - -typedef struct event_queue_t event_queue_t; - -/** - * The event queue facility can be used to synchronize thread-pool threads - * with the pluto main thread. That is, all queued callbacks are executed - * asynchronously by the pluto main thread. - */ -struct event_queue_t { - - /** - * Returns the file descriptor used to notify the main thread. - * - * @return fd to use in the main thread - */ - int (*get_event_fd) (event_queue_t *this); - - /** - * Handle all queued events. - */ - void (*handle) (event_queue_t *this); - - /** - * Add an event to the queue. - * - * @param callback callback function to add to the queue - * @param data data supplied to the callback function - * @param cleanup optional cleanup function - */ - void (*queue) (event_queue_t *this, void (*callback)(void *data), - void *data, void (*cleanup)(void *data)); - - /** - * Destroy this instance. - */ - void (*destroy) (event_queue_t *this); - -}; - -/** - * Create the event queue. - * - * @return created object - */ -event_queue_t *event_queue_create(); - -#endif /** EVENT_QUEUE_H_ @}*/ diff --git a/src/pluto/fetch.c b/src/pluto/fetch.c deleted file mode 100644 index 3dfc1386f..000000000 --- a/src/pluto/fetch.c +++ /dev/null @@ -1,766 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche - * Copyright (C) 2002-2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#ifdef THREADS -#include -#endif - -#include - -#include -#include -#include -#include -#ifdef THREADS -#include -#endif - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "ca.h" -#include "whack.h" -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "builder.h" - -fetch_req_t empty_fetch_req = { - NULL , /* next */ - 0 , /* trials */ - NULL , /* issuer */ - { NULL, 0}, /* authKeyID */ - NULL /* distributionPoints */ -}; - -/* chained list of crl fetch requests */ -static fetch_req_t *crl_fetch_reqs = NULL; - -/* chained list of ocsp fetch requests */ -static ocsp_location_t *ocsp_fetch_reqs = NULL; - -#ifdef THREADS -static thread_t *thread; -static pthread_mutex_t certs_and_keys_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t authcert_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_cache_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ca_info_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t crl_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t ocsp_fetch_list_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t fetch_wake_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t fetch_wake_cond = PTHREAD_COND_INITIALIZER; - -/** - * lock access to my certs and keys - */ -void lock_certs_and_keys(const char *who) -{ - pthread_mutex_lock(&certs_and_keys_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys locked by '%s'", who) - ) -} - -/** - * Unlock access to my certs and keys - */ -void unlock_certs_and_keys(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("certs and keys unlocked by '%s'", who) - ) - pthread_mutex_unlock(&certs_and_keys_mutex); -} - -/** - * Lock access to the chained authcert list - */ -void lock_authcert_list(const char *who) -{ - pthread_mutex_lock(&authcert_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("authcert list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained authcert list - */ -void unlock_authcert_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("authcert list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&authcert_list_mutex); -} - -/** - * Lock access to the chained crl list - */ -void lock_crl_list(const char *who) -{ - pthread_mutex_lock(&crl_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl list - */ -void unlock_crl_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_list_mutex); -} - -/** - * Lock access to the ocsp cache - */ -extern void lock_ocsp_cache(const char *who) -{ - pthread_mutex_lock(&ocsp_cache_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache locked by '%s'", who) - ) -} - -/** - * Unlock access to the ocsp cache - */ -extern void unlock_ocsp_cache(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp cache unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_cache_mutex); -} - -/** - * Lock access to the ca info list - */ -extern void lock_ca_info_list(const char *who) -{ - pthread_mutex_lock(&ca_info_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ca info list locked by '%s'", who) - ) -} - -/** - * Unlock access to the ca info list - */ -extern void unlock_ca_info_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ca info list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ca_info_list_mutex); -} - -/** - * Lock access to the chained crl fetch request list - */ -static void lock_crl_fetch_list(const char *who) -{ - pthread_mutex_lock(&crl_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained crl fetch request list - */ -static void unlock_crl_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("crl fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&crl_fetch_list_mutex); -} - -/** - * Lock access to the chained ocsp fetch request list - */ -static void lock_ocsp_fetch_list(const char *who) -{ - pthread_mutex_lock(&ocsp_fetch_list_mutex); - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list locked by '%s'", who) - ) -} - -/** - * Unlock access to the chained ocsp fetch request list - */ -static void unlock_ocsp_fetch_list(const char *who) -{ - DBG(DBG_CONTROLMORE, - DBG_log("ocsp fetch request list unlocked by '%s'", who) - ) - pthread_mutex_unlock(&ocsp_fetch_list_mutex); -} - -/** - * Wakes up the sleeping fetch thread - */ -void wake_fetch_thread(const char *who) -{ - if (crl_check_interval > 0) - { - DBG(DBG_CONTROLMORE, - DBG_log("fetch thread wake call by '%s'", who) - ) - pthread_mutex_lock(&fetch_wake_mutex); - pthread_cond_signal(&fetch_wake_cond); - pthread_mutex_unlock(&fetch_wake_mutex); - } -} -#else /* !THREADS */ -#define lock_crl_fetch_list(who) /* do nothing */ -#define unlock_crl_fetch_list(who) /* do nothing */ -#define lock_ocsp_fetch_list(who) /* do nothing */ -#define unlock_ocsp_fetch_list(who) /* do nothing */ -#endif /* !THREADS */ - -/** - * Free the dynamic memory used to store fetch requests - */ -static void free_fetch_request(fetch_req_t *req) -{ - req->distributionPoints->destroy_function(req->distributionPoints, free); - DESTROY_IF(req->issuer); - free(req->authKeyID.ptr); - free(req); -} - -#ifdef THREADS -/** - * Fetch an ASN.1 blob coded in PEM or DER format from a URL - */ -x509crl_t* fetch_crl(char *url) -{ - x509crl_t *crl; - chunk_t blob; - - DBG1(DBG_LIB, " fetching crl from '%s' ...", url); - if (lib->fetcher->fetch(lib->fetcher, url, &blob, FETCH_END) != SUCCESS) - { - DBG1(DBG_LIB, "crl fetching failed"); - return FALSE; - } - crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PLUTO_CRL, - BUILD_BLOB_PEM, blob, BUILD_END); - free(blob.ptr); - if (!crl) - { - DBG1(DBG_LIB, "crl fetched successfully but data coded in unknown " - "format"); - } - return crl; -} - -/** - * Complete a distributionPoint URI with ca information - */ -static char* complete_uri(char *distPoint, const char *ldaphost) -{ - char *symbol = strchr(distPoint, ':'); - - if (symbol) - { - int type_len = symbol - distPoint; - - if (type_len >= 4 && strncasecmp(distPoint, "ldap", 4) == 0) - { - char *ptr = symbol + 1; - int len = strlen(distPoint) - (type_len + 1); - - if (len > 2 && *ptr++ == '/' && *ptr++ == '/') - { - len -= 2; - symbol = strchr(ptr, '/'); - - if (symbol && symbol - ptr == 0 && ldaphost) - { - char uri[BUF_LEN]; - - /* insert the ldaphost into the uri */ - snprintf(uri, BUF_LEN, "%.*s%s%.*s", - (int)strlen(distPoint) - len, distPoint, ldaphost, - len, symbol); - return strdup(uri); - } - } - } - } - - /* default action: copy distributionPoint without change */ - return strdup(distPoint); -} - -/** - * Try to fetch the crls defined by the fetch requests - */ -static void fetch_crls(bool cache_crls) -{ - fetch_req_t *req; - fetch_req_t **reqp; - - lock_crl_fetch_list("fetch_crls"); - req = crl_fetch_reqs; - reqp = &crl_fetch_reqs; - - while (req != NULL) - { - enumerator_t *enumerator; - char *point; - bool valid_crl = FALSE; - const char *ldaphost; - ca_info_t *ca; - - lock_ca_info_list("fetch_crls"); - - ca = get_ca_info(req->issuer, req->authKeyID); - ldaphost = (ca == NULL)? NULL : ca->ldaphost; - - enumerator = req->distributionPoints->create_enumerator(req->distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - x509crl_t *crl; - char *uri; - - uri = complete_uri(point, ldaphost); - crl = fetch_crl(uri); - free(uri); - - if (crl) - { - if (insert_crl(crl, point, cache_crls)) - { - DBG(DBG_CONTROL, - DBG_log("we have a valid crl") - ) - valid_crl = TRUE; - break; - } - } - } - enumerator->destroy(enumerator); - unlock_ca_info_list("fetch_crls"); - - if (valid_crl) - { - /* delete fetch request */ - fetch_req_t *req_free = req; - - req = req->next; - *reqp = req; - free_fetch_request(req_free); - } - else - { - /* try again next time */ - req->trials++; - reqp = &req->next; - req = req->next; - } - } - unlock_crl_fetch_list("fetch_crls"); -} - -static void fetch_ocsp_status(ocsp_location_t* location) -{ - chunk_t request = build_ocsp_request(location); - chunk_t response = chunk_empty; - - DBG1(DBG_LIB, " requesting ocsp status from '%s' ...", location->uri); - if (lib->fetcher->fetch(lib->fetcher, location->uri, &response, - FETCH_REQUEST_DATA, request, - FETCH_REQUEST_TYPE, "application/ocsp-request", - FETCH_END) == SUCCESS) - { - parse_ocsp(location, response); - } - else - { - DBG1(DBG_LIB, "ocsp request to %s failed", location->uri); - } - - free(request.ptr); - chunk_free(&location->nonce); - - /* increment the trial counter of the unresolved fetch requests */ - { - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo != NULL) - { - certinfo->trials++; - certinfo = certinfo->next; - } - } -} - -/** - * Try to fetch the necessary ocsp information - */ -static void fetch_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_fetch_list("fetch_ocsp"); - location = ocsp_fetch_reqs; - - /* fetch the ocps status for all locations */ - while (location != NULL) - { - if (location->certinfo != NULL) - { - fetch_ocsp_status(location); - } - location = location->next; - } - - unlock_ocsp_fetch_list("fetch_ocsp"); -} - -static void* fetch_thread(void *arg) -{ - struct timespec wait_interval; - - /* the fetching thread is only cancellable while waiting for new events */ - thread_cancelability(FALSE); - - DBG(DBG_CONTROL, - DBG_log("fetch thread started") - ) - - pthread_mutex_lock(&fetch_wake_mutex); - - while(1) - { - int status; - - wait_interval.tv_nsec = 0; - wait_interval.tv_sec = time(NULL) + crl_check_interval; - - DBG(DBG_CONTROL, - DBG_log("next regular crl check in %ld seconds", crl_check_interval) - ) - - thread_cancelability(TRUE); - status = pthread_cond_timedwait(&fetch_wake_cond, &fetch_wake_mutex - , &wait_interval); - thread_cancelability(FALSE); - - if (status == ETIMEDOUT) - { - DBG(DBG_CONTROL, - DBG_log(" "); - DBG_log("*time to check crls and the ocsp cache") - ) - check_ocsp(); - check_crls(); - } - else - { - DBG(DBG_CONTROL, - DBG_log("fetch thread was woken up") - ) - } - fetch_ocsp(); - fetch_crls(cache_crls); - } - return NULL; -} -#endif /* THREADS*/ - -/** - * Initializes curl and starts the fetching thread - */ -void fetch_initialize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - thread = thread_create((thread_main_t)fetch_thread, NULL); - if (thread == NULL) - { - plog("fetching thread could not be started"); - } -#else /* !THREADS */ - plog("warning: not compiled with pthread support"); -#endif /* !THREADS */ - } -} - -/** - * Terminates the fetching thread - */ -void fetch_finalize(void) -{ - if (crl_check_interval > 0) - { -#ifdef THREADS - if (thread) - { - thread->cancel(thread); - thread->join(thread); - } -#endif - } -} - -void free_crl_fetch(void) -{ - lock_crl_fetch_list("free_crl_fetch"); - - while (crl_fetch_reqs != NULL) - { - fetch_req_t *req = crl_fetch_reqs; - crl_fetch_reqs = req->next; - free_fetch_request(req); - } - - unlock_crl_fetch_list("free_crl_fetch"); -} - -/** - * Free the chained list of ocsp requests - */ -void free_ocsp_fetch(void) -{ - lock_ocsp_fetch_list("free_ocsp_fetch"); - free_ocsp_locations(&ocsp_fetch_reqs); - unlock_ocsp_fetch_list("free_ocsp_fetch"); -} - - -/** - * Add an additional distribution point - */ -void add_distribution_point(linked_list_t *points, char *new_point) -{ - char *point; - bool add = TRUE; - enumerator_t *enumerator; - - if (new_point == NULL || *new_point == '\0') - { - return; - } - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } -} - -/** - * Add additional distribution points - */ -void add_distribution_points(linked_list_t *points, linked_list_t *new_points) -{ - char *new_point; - enumerator_t *enumerator; - - enumerator = new_points->create_enumerator(new_points); - while (enumerator->enumerate(enumerator, &new_point)) - { - bool add = TRUE; - char *point; - enumerator_t *enumerator; - - enumerator = points->create_enumerator(points); - while (enumerator->enumerate(enumerator, &point)) - { - if (streq(point, new_point)) - { - add = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (add) - { - points->insert_last(points, strdup(new_point)); - } - } - enumerator->destroy(enumerator); -} - -fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints) -{ - char *point; - enumerator_t *enumerator; - fetch_req_t *req = malloc_thing(fetch_req_t); - - memset(req, 0, sizeof(fetch_req_t)); - req->distributionPoints = linked_list_create(); - - /* clone fields */ - req->issuer = issuer->clone(issuer); - req->authKeyID = chunk_clone(authKeyID); - - /* copy distribution points */ - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - req->distributionPoints->insert_last(req->distributionPoints, - strdup(point)); - } - enumerator->destroy(enumerator); - - return req; -} - -/** - * Add a crl fetch request to the chained list - */ -void add_crl_fetch_request(fetch_req_t *req) -{ - fetch_req_t *r; - - lock_crl_fetch_list("add_crl_fetch_request"); - r = crl_fetch_reqs; - - while (r != NULL) - { - if (req->authKeyID.ptr ? same_keyid(req->authKeyID, r->authKeyID) : - req->issuer->equals(req->issuer, r->issuer)) - { - /* there is already a fetch request */ - DBG(DBG_CONTROL, - DBG_log("crl fetch request already exists") - ) - - /* there might be new distribution points */ - add_distribution_points(r->distributionPoints, - req->distributionPoints); - - unlock_crl_fetch_list("add_crl_fetch_request"); - free_fetch_request(req); - return; - } - r = r->next; - } - - /* insert new fetch request at the head of the queue */ - req->next = crl_fetch_reqs; - crl_fetch_reqs = req; - - DBG(DBG_CONTROL, - DBG_log("crl fetch request added") - ) - unlock_crl_fetch_list("add_crl_fetch_request"); -} - -/** - * Add an ocsp fetch request to the chained list - */ -void add_ocsp_fetch_request(ocsp_location_t *location, chunk_t serialNumber) -{ - ocsp_certinfo_t certinfo; - - certinfo.serialNumber = serialNumber; - - lock_ocsp_fetch_list("add_ocsp_fetch_request"); - add_certinfo(location, &certinfo, &ocsp_fetch_reqs, TRUE); - unlock_ocsp_fetch_list("add_ocsp_fetch_request"); -} - -/** - * List all distribution points - */ -void list_distribution_points(linked_list_t *distributionPoints) -{ - char *point; - bool first_point = TRUE; - enumerator_t *enumerator; - - enumerator = distributionPoints->create_enumerator(distributionPoints); - while (enumerator->enumerate(enumerator, &point)) - { - whack_log(RC_COMMENT, " %s '%s'", - (first_point)? "distPts: " : " ", point); - first_point = FALSE; - } - enumerator->destroy(enumerator); -} - -/** - * List all fetch requests in the chained list - */ -void list_crl_fetch_requests(bool utc) -{ - fetch_req_t *req; - - lock_crl_fetch_list("list_crl_fetch_requests"); - req = crl_fetch_reqs; - - if (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of CRL Fetch Requests:"); - } - - while (req != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " trials: %d", req->trials); - whack_log(RC_COMMENT, " issuer: \"%Y\"", req->issuer); - if (req->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &req->authKeyID); - } - list_distribution_points(req->distributionPoints); - req = req->next; - } - unlock_crl_fetch_list("list_crl_fetch_requests"); -} - -void list_ocsp_fetch_requests(bool utc) -{ - lock_ocsp_fetch_list("list_ocsp_fetch_requests"); - list_ocsp_locations(ocsp_fetch_reqs, TRUE, utc, FALSE); - unlock_ocsp_fetch_list("list_ocsp_fetch_requests"); - -} diff --git a/src/pluto/fetch.h b/src/pluto/fetch.h deleted file mode 100644 index 265dc5fe7..000000000 --- a/src/pluto/fetch.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Dynamic fetching of X.509 CRLs - * Copyright (C) 2002 Stephane Laroche - * Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include "x509.h" - -#define FETCH_CMD_TIMEOUT 10 /* seconds */ - -struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */ - -typedef enum { - FETCH_GET = 1, - FETCH_POST = 2 -} fetch_request_t; - -typedef struct fetch_req fetch_req_t; - -struct fetch_req { - fetch_req_t *next; - int trials; - identification_t *issuer; - chunk_t authKeyID; - linked_list_t *distributionPoints; -}; - -#ifdef THREADS -extern void lock_crl_list(const char *who); -extern void unlock_crl_list(const char *who); -extern void lock_ocsp_cache(const char *who); -extern void unlock_ocsp_cache(const char *who); -extern void lock_ca_info_list(const char *who); -extern void unlock_ca_info_list(const char *who); -extern void lock_authcert_list(const char *who); -extern void unlock_authcert_list(const char *who); -extern void lock_certs_and_keys(const char *who); -extern void unlock_certs_and_keys(const char *who); -extern void wake_fetch_thread(const char *who); -#else -#define lock_crl_list(who) /* do nothing */ -#define unlock_crl_list(who) /* do nothing */ -#define lock_ocsp_cache(who) /* do nothing */ -#define unlock_ocsp_cache(who) /* do nothing */ -#define lock_ca_info_list(who) /* do nothing */ -#define unlock_ca_info_list(who) /* do nothing */ -#define lock_authcert_list(who) /* do nothing */ -#define unlock_authcert_list(who) /* do nothing */ -#define lock_certs_and_keys(who) /* do nothing */ -#define unlock_certs_and_keys(who) /* do nothing */ -#define wake_fetch_thread(who) /* do nothing */ -#endif -extern void fetch_initialize(void); -extern void fetch_finalize(void); -extern void free_crl_fetch(void); -extern void free_ocsp_fetch(void); -extern void add_distribution_point(linked_list_t *points, char* new_point); -extern void add_distribution_points(linked_list_t *points, - linked_list_t *new_points); -extern fetch_req_t* build_crl_fetch_request(identification_t *issuer, - chunk_t authKeyID, - linked_list_t *distributionPoints); -extern void add_crl_fetch_request(fetch_req_t *req); -extern void add_ocsp_fetch_request(struct ocsp_location *location, - chunk_t serialNumber); -extern void list_distribution_points(linked_list_t *distributionPoints); -extern void list_crl_fetch_requests(bool utc); -extern void list_ocsp_fetch_requests(bool utc); -extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data); - diff --git a/src/pluto/foodgroups.c b/src/pluto/foodgroups.c deleted file mode 100644 index e4f9a1d01..000000000 --- a/src/pluto/foodgroups.c +++ /dev/null @@ -1,450 +0,0 @@ -/* Implement policy groups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "foodgroups.h" -#include "kernel.h" -#include "lex.h" -#include "log.h" -#include "whack.h" - - -/* Food group config files are found in directory fg_path */ - -#ifndef POLICYGROUPSDIR -#define POLICYGROUPSDIR IPSEC_CONFDIR "/ipsec.d/policies" -#endif - -const char *policygroups_dir = POLICYGROUPSDIR; - -static char *fg_path = NULL; -static size_t fg_path_space = 0; - - -/* Groups is a list of connections that are policy groups. - * The list is updated as group connections are added and deleted. - */ - -struct fg_groups { - struct fg_groups *next; - connection_t *connection; -}; - -static struct fg_groups *groups = NULL; - - -/* Targets is a list of pairs: subnet and its policy group. - * This list is bulk-updated on whack --listen and - * incrementally updated when group connections are deleted. - * - * It is ordered by source subnet, and if those are equal, then target subnet. - * A subnet is compared by comparing the network, and if those are equal, - * comparing the mask. - */ - -struct fg_targets { - struct fg_targets *next; - struct fg_groups *group; - ip_subnet subnet; - char *name; /* name of instance of group conn */ -}; - -static struct fg_targets *targets = NULL; - -struct fg_targets *new_targets; - -/* ipcmp compares the two ip_address values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int ipcmp(ip_address *a, ip_address *b) -{ - if (addrtypeof(a) != addrtypeof(b)) - { - return addrtypeof(a) < addrtypeof(b)? -1 : 1; - } - else if (sameaddr(a, b)) - { - return 0; - } - else - { - const struct sockaddr *sa = sockaddrof(a) - , *sb = sockaddrof(b); - - passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */ - return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr) - < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr)) - ? -1 : 1; - } -} - -/* subnetcmp compares the two ip_subnet values a and b. - * It returns -1, 0, or +1 if a is, respectively, - * less than, equal to, or greater than b. - */ -static int subnetcmp(const ip_subnet *a, const ip_subnet *b) -{ - ip_address neta, maska, netb, maskb; - int r; - - networkof(a, &neta); - maskof(a, &maska); - networkof(b, &netb); - maskof(b, &maskb); - r = ipcmp(&neta, &netb); - if (r == 0) - r = ipcmp(&maska, &maskb); - return r; -} - -static void read_foodgroup(struct fg_groups *g) -{ - const char *fgn = g->connection->name; - const ip_subnet *lsn = &g->connection->spd.this.client; - size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1; - struct file_lex_position flp_space; - - if (plen > fg_path_space) - { - free(fg_path); - fg_path_space = plen + 10; - fg_path = malloc(fg_path_space); - } - snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn); - if (!lexopen(&flp_space, fg_path, TRUE)) - { - DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path)); - } - else - { - plog("loading group \"%s\"", fg_path); - for (;;) - { - switch (flp->bdry) - { - case B_none: - { - /* !!! this test is not sufficient for distinguishing address families. - * We need a notation to specify that a FQDN is to be resolved to IPv6. - */ - const struct af_info *afi = strchr(tok, ':') == NULL - ? &af_inet4_info: &af_inet6_info; - ip_subnet sn; - err_t ugh; - - if (strchr(tok, '/') == NULL) - { - /* no /, so treat as /32 or V6 equivalent */ - ip_address t; - - ugh = ttoaddr(tok, 0, afi->af, &t); - if (ugh == NULL) - ugh = addrtosubnet(&t, &sn); - } - else - { - ugh = ttosubnet(tok, 0, afi->af, &sn); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\"" - , flp->filename, flp->lino, ugh, tok); - } - else if (afi->af != AF_INET) - { - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: unsupported Address Family \"%s\"" - , flp->filename, flp->lino, tok); - } - else - { - /* Find where new entry ought to go in new_targets. */ - struct fg_targets **pp; - int r; - - for (pp = &new_targets; ; pp = &(*pp)->next) - { - if (*pp == NULL) - { - r = -1; /* end of list is infinite */ - break; - } - r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client); - if (r == 0) - r = subnetcmp(&sn, &(*pp)->subnet); - if (r <= 0) - break; - } - - if (r == 0) - { - char source[SUBNETTOT_BUF]; - - subnettot(lsn, 0, source, sizeof(source)); - loglog(RC_LOG_SERIOUS - , "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\"" - , flp->filename - , flp->lino - , tok - , source - , (*pp)->group->connection->name); - } - else - { - struct fg_targets *f = malloc_thing(struct fg_targets); - - f->next = *pp; - f->group = g; - f->subnet = sn; - f->name = NULL; - *pp = f; - } - } - } - (void)shift(); /* next */ - continue; - - case B_record: - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - continue; - - case B_file: - break; /* done */ - } - break; /* if we reach here, out of loop */ - } - lexclose(); - } -} - -static void free_targets(void) -{ - while (targets != NULL) - { - struct fg_targets *t = targets; - - targets = t->next; - free(t->name); - free(t); - } -} - -void load_groups(void) -{ - passert(new_targets == NULL); - - /* for each group, add config file targets into new_targets */ - { - struct fg_groups *g; - - for (g = groups; g != NULL; g = g->next) - if (oriented(*g->connection)) - read_foodgroup(g); - } - - /* dump new_targets */ - DBG(DBG_CONTROL, - { - struct fg_targets *t; - - for (t = new_targets; t != NULL; t = t->next) - { - char asource[SUBNETTOT_BUF]; - char atarget[SUBNETTOT_BUF]; - - subnettot(&t->group->connection->spd.this.client - , 0, asource, sizeof(asource)); - subnettot(&t->subnet, 0, atarget, sizeof(atarget)); - DBG_log("%s->%s %s" - , asource, atarget - , t->group->connection->name); - } - }); - - /* determine and deal with differences between targets and new_targets. - * structured like a merge. - */ - { - struct fg_targets *op = targets - , *np = new_targets; - - while (op != NULL && np != NULL) - { - int r = subnetcmp(&op->group->connection->spd.this.client - , &np->group->connection->spd.this.client); - - if (r == 0) - r = subnetcmp(&op->subnet, &np->subnet); - - if (r == 0 && op->group == np->group) - { - /* unchanged -- steal name & skip over */ - np->name = op->name; - op->name = NULL; - op = op->next; - np = np->next; - } - else - { - /* note: following cases overlap! */ - if (r <= 0) - { - remove_group_instance(op->group->connection, op->name); - op = op->next; - } - if (r >= 0) - { - np->name = add_group_instance(np->group->connection, &np->subnet); - np = np->next; - } - } - } - for (; op != NULL; op = op->next) - remove_group_instance(op->group->connection, op->name); - for (; np != NULL; np = np->next) - np->name = add_group_instance(np->group->connection, &np->subnet); - - /* update: new_targets replaces targets */ - free_targets(); - targets = new_targets; - new_targets = NULL; - } -} - - -void add_group(connection_t *c) -{ - struct fg_groups *g = malloc_thing(struct fg_groups); - - g->next = groups; - groups = g; - - g->connection = c; -} - -static struct fg_groups *find_group(const connection_t *c) -{ - struct fg_groups *g; - - for (g = groups; g != NULL && g->connection != c; g = g->next) - ; - return g; -} - -void route_group(connection_t *c) -{ - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection"); - } - else - { - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy |= POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - if (!trap_connection(ci)) - whack_log(RC_ROUTE, "could not route"); - set_cur_connection(c); - } - } - } - } -} - -void unroute_group(connection_t *c) -{ - struct fg_groups *g = find_group(c); - struct fg_targets *t; - - passert(g != NULL); - g->connection->policy &= ~POLICY_GROUTED; - for (t = targets; t != NULL; t = t->next) - { - if (t->group == g) - { - connection_t *ci = con_by_name(t->name, FALSE); - - if (ci != NULL) - { - set_cur_connection(ci); - unroute_connection(ci); - set_cur_connection(c); - } - } - } -} - -void delete_group(const connection_t *c) -{ - struct fg_groups *g; - - /* find and remove from groups */ - { - struct fg_groups **pp; - - for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next) - ; - - *pp = g->next; - } - - /* find and remove from targets */ - { - struct fg_targets **pp; - - for (pp = &targets; *pp != NULL; ) - { - struct fg_targets *t = *pp; - - if (t->group == g) - { - *pp = t->next; - remove_group_instance(t->group->connection, t->name); - free(t); - /* pp is ready for next iteration */ - } - else - { - pp = &t->next; - } - } - } - - free(g); -} diff --git a/src/pluto/foodgroups.h b/src/pluto/foodgroups.h deleted file mode 100644 index b6d3386ae..000000000 --- a/src/pluto/foodgroups.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Implement policygroups-style control files (aka "foodgroups") - * Copyright (C) 2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -struct connection; /* forward declaration */ -extern void add_group(struct connection *c); -extern void route_group(struct connection *c); -extern void unroute_group(struct connection *c); -extern void delete_group(const struct connection *c); - -extern const char *policygroups_dir; -extern void load_groups(void); diff --git a/src/pluto/ike_alg.c b/src/pluto/ike_alg.c deleted file mode 100644 index 3061630e0..000000000 --- a/src/pluto/ike_alg.c +++ /dev/null @@ -1,452 +0,0 @@ -/* IKE modular algorithm handling interface - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "crypto.h" -#include "state.h" -#include "packet.h" -#include "keys.h" -#include "log.h" -#include "whack.h" -#include "spdb.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "db_ops.h" -#include "connections.h" -#include "kernel.h" - -#define return_on(var, val) do { var=val;goto return_out; } while(0); - -/** - * IKE algorithm list handling - registration and lookup - */ - -/* Modular IKE algorithm storage structure */ - -static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL}; - -/** - * Return ike_algo object by {type, id} - */ -static struct ike_alg *ike_alg_find(u_int algo_type, u_int algo_id, - u_int keysize __attribute__((unused))) -{ - struct ike_alg *e = ike_alg_base[algo_type]; - - while (e != NULL && algo_id > e->algo_id) - { - e = e->algo_next; - } - return (e != NULL && e->algo_id == algo_id) ? e : NULL; -} - -/** - * "raw" ike_alg list adding function - */ -int ike_alg_add(struct ike_alg* a, const char *plugin_name) -{ - if (a->algo_type > IKE_ALG_MAX) - { - plog("ike_alg: Not added, invalid algorithm type"); - return -EINVAL; - } - - if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL) - { - plog("ike_alg: Not added, algorithm already exists"); - return -EEXIST; - } - - { - struct ike_alg **ep = &ike_alg_base[a->algo_type]; - struct ike_alg *e = *ep; - - while (e != NULL && a->algo_id > e->algo_id) - { - ep = &e->algo_next; - e = *ep; - } - *ep = a; - a->plugin_name = plugin_name; - a->algo_next = e; - return 0; - } -} - -/** - * Get IKE hash algorithm - */ -struct hash_desc *ike_alg_get_hasher(u_int alg) -{ - return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0); -} - -/** - * Get IKE encryption algorithm - */ -struct encrypt_desc *ike_alg_get_crypter(u_int alg) -{ - return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0); -} - -/** - * Get IKE dh group - */ -struct dh_desc *ike_alg_get_dh_group(u_int alg) -{ - return (struct dh_desc *) ike_alg_find(IKE_ALG_DH_GROUP, alg, 0); -} - -/** - * Get pfsgroup for this connection - */ -const struct dh_desc *ike_alg_pfsgroup(connection_t *c, lset_t policy) -{ - const struct dh_desc *ret = NULL; - - if ((policy & POLICY_PFS) && - c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) - { - ret = ike_alg_get_dh_group(c->alg_info_esp->esp_pfsgroup); - } - return ret; -} - -/** - * Create an OAKLEY proposal based on alg_info and policy - */ -struct db_context *ike_alg_db_new(connection_t *c, lset_t policy) -{ - struct alg_info_ike *ai = c->alg_info_ike; - struct db_context *db_ctx = NULL; - struct ike_info *ike_info; - u_int ealg, halg, modp, eklen = 0; - int i; - - bool is_xauth_server = (policy & POLICY_XAUTH_SERVER) != LEMPTY; - - if (!ai) - { - whack_log(RC_LOG_SERIOUS, "no IKE algorithms " - "for this connection " - "(check ike algorithm string)"); - goto fail; - } - policy &= POLICY_ID_AUTH_MASK; - db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5); - - /* for each group */ - ALG_INFO_IKE_FOREACH(ai, ike_info, i) - { - ealg = ike_info->ike_ealg; - halg = ike_info->ike_halg; - modp = ike_info->ike_modp; - eklen= ike_info->ike_eklen; - - if (!ike_alg_get_crypter(ealg)) - { - plog("ike alg: crypter %s not present", - enum_show(&oakley_enc_names, ealg)); - continue; - } - if (!ike_alg_get_hasher(halg)) - { - plog("ike alg: hasher %s not present", - enum_show(&oakley_hash_names, halg)); - continue; - } - if (!ike_alg_get_dh_group(modp)) - { - plog("ike alg: dh group %s not present", - enum_show(&oakley_group_names, modp)); - continue; - } - - if (policy & POLICY_PUBKEY) - { - int auth_method = 0, key_size = 0; - key_type_t key_type = KEY_ANY; - - if (c->spd.this.cert) - { - certificate_t *certificate = c->spd.this.cert->cert; - public_key_t *key = certificate->get_public_key(certificate); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my public key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - key->destroy(key); - } - else - { - private_key_t *key = get_private_key(c); - - if (key == NULL) - { - plog("ike alg: unable to retrieve my private key"); - continue; - } - key_type = key->get_type(key); - key_size = key->get_keysize(key); - } - switch (key_type) - { - case KEY_RSA: - auth_method = OAKLEY_RSA_SIG; - break; - case KEY_ECDSA: - switch (key_size) - { - case 256: - auth_method = OAKLEY_ECDSA_256; - break; - case 384: - auth_method = OAKLEY_ECDSA_384; - break; - case 521: - auth_method = OAKLEY_ECDSA_521; - break; - default: - continue; - } - break; - default: - continue; - } - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, auth_method); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_RSASIG) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespRSA : XAUTHInitRSA); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - - if (policy & POLICY_XAUTH_PSK) - { - db_trans_add(db_ctx, KEY_IKE); - db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg); - db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg); - if (eklen) - { - db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen); - } - db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD - , is_xauth_server ? XAUTHRespPreShared : XAUTHInitPreShared); - db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp); - } - } -fail: - return db_ctx; -} - -/** - * Print the name of an algorithm plus the name of the plugin that registered it - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type, - const char *plugin_name) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s[%s]", enum_name(alg_names, alg_type), - plugin_name); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -/** - * Show registered IKE algorithms - */ -void ike_alg_list(void) -{ - rng_quality_t quality; - enumerator_t *enumerator; - const char *plugin_name; - char buf[BUF_LEN]; - int len; - struct ike_alg *a; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered IKEv1 Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_enc_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_hash_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " dh-group: "); - for (a = ike_alg_base[IKE_ALG_DH_GROUP]; a != NULL; a = a->algo_next) - { - print_alg(buf, &len, &oakley_group_names, a->algo_id, a->plugin_name); - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " random-gen:"); - enumerator = lib->crypto->create_rng_enumerator(lib->crypto); - while (enumerator->enumerate(enumerator, &quality, &plugin_name)) - { - len += sprintf(buf + len, " %N[%s]", rng_quality_names, quality, - plugin_name); - } - enumerator->destroy(enumerator); - whack_log(RC_COMMENT, "%s", buf); -} - -/** - * Show IKE algorithms for this connection (result from ike= string) - * and newest SA - */ -void ike_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_isakmp_sa); - - if (st) - { - if (st->st_oakley.encrypt == OAKLEY_3DES_CBC) - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - else - { - whack_log(RC_COMMENT, - "\"%s\"%s: IKE proposal: %s_%u/%s/%s", - c->name, instance, - enum_show(&oakley_enc_names, st->st_oakley.encrypt), - st->st_oakley.enckeylen, - enum_show(&oakley_hash_names, st->st_oakley.hash), - enum_show(&oakley_group_names, st->st_oakley.group->algo_id) - ); - } - } -} - -/** - * ML: make F_STRICT logic consider enc,hash/auth,modp algorithms - */ -bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group, - struct alg_info_ike *alg_info_ike) -{ - /* - * simple test to discard low key_len, will accept it only - * if specified in "esp" string - */ - bool ealg_insecure = (key_len < 128); - - if (ealg_insecure - || (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct ike_info *ike_info; - - if (alg_info_ike) - { - ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i) - { - if (ike_info->ike_ealg == ealg - && (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len) - && ike_info->ike_halg == aalg - && ike_info->ike_modp == group) - { - if (ealg_insecure) - loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!" - , enum_name(&oakley_enc_names, ealg)); - return TRUE; - } - } - } - plog("Oakley Transform [%s (%d), %s, %s] refused due to %s" - , enum_name(&oakley_enc_names, ealg), key_len - , enum_name(&oakley_hash_names, aalg) - , enum_name(&oakley_group_names, group) - , ealg_insecure ? - "insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag" - ); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/ike_alg.h b/src/pluto/ike_alg.h deleted file mode 100644 index c3ce8bb38..000000000 --- a/src/pluto/ike_alg.h +++ /dev/null @@ -1,76 +0,0 @@ -/* IKE modular algorithm handling interface - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IKE_ALG_H -#define _IKE_ALG_H - -#include - -#include "connections.h" - -struct ike_alg { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; -}; - -struct encrypt_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t enc_blocksize; - u_int keydeflen; - u_int keymaxlen; - u_int keyminlen; -}; - -struct hash_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t hash_digest_size; -}; - -struct dh_desc { - u_int16_t algo_type; - u_int16_t algo_id; - const char *plugin_name; - struct ike_alg *algo_next; - - size_t ke_size; -}; - -#define IKE_ALG_ENCRYPT 0 -#define IKE_ALG_HASH 1 -#define IKE_ALG_DH_GROUP 2 -#define IKE_ALG_MAX IKE_ALG_DH_GROUP - -extern int ike_alg_add(struct ike_alg *a, const char *plugin_name); -extern struct hash_desc *ike_alg_get_hasher(u_int alg); -extern struct encrypt_desc *ike_alg_get_crypter(u_int alg); -extern struct dh_desc *ike_alg_get_dh_group(u_int alg); -extern const struct dh_desc* ike_alg_pfsgroup(struct connection *c, lset_t policy); -extern struct db_context * ike_alg_db_new(struct connection *c, lset_t policy); -extern void ike_alg_list(void); -extern void ike_alg_show_connection(struct connection *c, const char *instance); -extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group - , struct alg_info_ike *alg_info_ike); -extern int ike_alg_init(void); - -#endif /* _IKE_ALG_H */ diff --git a/src/pluto/ipsec_doi.c b/src/pluto/ipsec_doi.c deleted file mode 100644 index 3e7adcc40..000000000 --- a/src/pluto/ipsec_doi.c +++ /dev/null @@ -1,5921 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "state.h" -#include "x509.h" -#include "ac.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "keys.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "kernel.h" -#include "log.h" -#include "cookie.h" -#include "server.h" -#include "spdb.h" -#include "timer.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "whack.h" -#include "fetch.h" -#include "pkcs7.h" -#include "crypto.h" -#include "vendor.h" -#include "alg_info.h" -#include "ike_alg.h" -#include "kernel_alg.h" -#include "nat_traversal.h" -#include "virtual.h" - -/* - * are we sending Pluto's Vendor ID? - */ -#ifdef VENDORID -#define SEND_PLUTO_VID 1 -#else /* !VENDORID */ -#define SEND_PLUTO_VID 0 -#endif /* !VENDORID */ - -/* - * are we sending an XAUTH VID? - */ -#ifdef XAUTH_VID -#define SEND_XAUTH_VID 1 -#else /* !XAUTH_VID */ -#define SEND_XAUTH_VID 0 -#endif /* !XAUTH_VID */ - -/* - * are we sending a Cisco Unity VID? - */ -#ifdef CISCO_QUIRKS -#define SEND_CISCO_UNITY_VID 1 -#else /* !CISCO_QUIRKS */ -#define SEND_CISCO_UNITY_VID 0 -#endif /* !CISCO_QUIRKS */ - -/* MAGIC: perform f, a function that returns notification_t - * and return from the ENCLOSING stf_status returning function if it fails. - */ -#define RETURN_STF_FAILURE(f) \ - { int r = (f); if (r != ISAKMP_NOTHING_WRONG) return STF_FAIL + r; } - -/* The endpoint(s) for which an SA is getting installed, so keying material - * can be properly wiped. - */ -enum endpoint { - EP_LOCAL = 1, - EP_REMOTE = 1 << 1, -}; - -/* create output HDR as replica of input HDR */ -void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np) -{ - struct isakmp_hdr r_hdr = md->hdr; /* mostly same as incoming header */ - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - if (enc) - { - r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION; - } - /* some day, we may have to set r_hdr.isa_version */ - r_hdr.isa_np = np; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - { - impossible(); /* surely must have room and be well-formed */ - } -} - -/* Compute DH shared secret from our local secret and the peer's public value. - * We make the leap that the length should be that of the group - * (see quoted passage at start of ACCEPT_KE). - */ -static void compute_dh_shared(struct state *st, const chunk_t g) -{ - passert(st->st_dh); - st->st_dh->set_other_public_value(st->st_dh, g); - st->st_dh->get_shared_secret(st->st_dh, &st->st_shared); - DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared); -} - -/* if we haven't already done so, compute a local DH secret (st->st_sec) and - * the corresponding public value (g). This is emitted as a KE payload. - */ -static bool build_and_ship_KE(struct state *st, chunk_t *g, - const struct dh_desc *group, - pb_stream *outs, u_int8_t np) -{ - if (st->st_dh == NULL) - { - st->st_dh = lib->crypto->create_dh(lib->crypto, group->algo_id); - if (st->st_dh == NULL) - { - plog("Diffie Hellman group %N is not available", - diffie_hellman_group_names, group->algo_id); - return FALSE; - } - } - st->st_dh->get_my_public_value(st->st_dh, g); - DBG(DBG_CRYPT, - DBG_dump_chunk("Public DH value sent:\n", *g) - ) - return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value"); -} - -/* accept_ke - * - * Check and accept DH public value (Gi or Gr) from peer's message. - * According to RFC2409 "The Internet key exchange (IKE)" 5: - * The Diffie-Hellman public value passed in a KE payload, in either - * a phase 1 or phase 2 exchange, MUST be the length of the negotiated - * Diffie-Hellman group enforced, if necessary, by pre-pending the - * value with zeros. - */ -static notification_t accept_KE(chunk_t *dest, const char *val_name, - const struct dh_desc *gr, - pb_stream *pbs) -{ - if (pbs_left(pbs) != gr->ke_size) - { - loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required" - , (unsigned) pbs_left(pbs), gr->ke_size); - /* XXX Could send notification back */ - return ISAKMP_INVALID_KEY_INFORMATION; - } - free(dest->ptr); - *dest = chunk_create(pbs->cur, pbs_left(pbs)); - *dest = chunk_clone(*dest); - DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest); - return ISAKMP_NOTHING_WRONG; -} - -/* accept_PFS_KE - * - * Check and accept optional Quick Mode KE payload for PFS. - * Extends ACCEPT_PFS to check whether KE is allowed or required. - */ -static notification_t accept_PFS_KE(struct msg_digest *md, chunk_t *dest, - const char *val_name, const char *msg_name) -{ - struct state *st = md->st; - struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE]; - - if (ke_pd == NULL) - { - if (st->st_pfs_group != NULL) - { - loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - } - else - { - if (st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA" - , msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; - } - if (ke_pd->next != NULL) - { - loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name); - return ISAKMP_INVALID_KEY_INFORMATION; /* ??? */ - } - return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs); - } - return ISAKMP_NOTHING_WRONG; -} - -static bool build_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np, - const char *name) -{ - rng_t *rng; - - free(n->ptr); - *n = chunk_create(malloc(DEFAULT_NONCE_SIZE), DEFAULT_NONCE_SIZE); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, DEFAULT_NONCE_SIZE, n->ptr); - rng->destroy(rng); - return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name); -} - -static linked_list_t* collect_rw_ca_candidates(struct msg_digest *md) -{ - linked_list_t *list = linked_list_create(); - connection_t *d; - - d = find_host_connection(&md->iface->addr, pluto_port, (ip_address*)NULL, - md->sender_port, LEMPTY); - - for (; d != NULL; d = d->hp_next) - { - /* must be a road warrior connection */ - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO) && - d->spd.that.ca) - { - enumerator_t *enumerator; - identification_t *ca; - bool new_entry = TRUE; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (ca->equals(ca, d->spd.that.ca)) - { - new_entry = FALSE; - break; - } - } - enumerator->destroy(enumerator); - - if (new_entry) - { - list->insert_last(list, d->spd.that.ca->clone(d->spd.that.ca)); - } - } - } - return list; -} - -static bool build_and_ship_CR(u_int8_t type, chunk_t ca, pb_stream *outs, - u_int8_t np) -{ - pb_stream cr_pbs; - struct isakmp_cr cr_hd; - cr_hd.isacr_np = np; - cr_hd.isacr_type = type; - - /* build CR header */ - if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs)) - { - return FALSE; - } - if (ca.ptr != NULL) - { - /* build CR body containing the distinguished name of the CA */ - if (!out_chunk(ca, &cr_pbs, "CA")) - return FALSE; - } - close_output_pbs(&cr_pbs); - return TRUE; -} - -/* Send a notification to the peer. We could decide - * whether to send the notification, based on the type and the - * destination, if we care to. - */ -static void send_notification(struct state *sndst, u_int16_t type, - struct state *encst, msgid_t msgid, - u_char *icookie, u_char *rcookie, - u_char *spi, size_t spisize, u_char protoid) -{ - u_char buffer[1024]; - pb_stream pbs, r_hdr_pbs; - u_char *r_hashval = NULL; /* where in reply to jam hash value */ - u_char *r_hash_start = NULL; /* start of what is to be hashed */ - - passert((sndst) && (sndst->st_connection)); - - plog("sending %snotification %s to %s:%u" - , encst ? "encrypted " : "" - , enum_name(¬ification_names, type) - , ip_str(&sndst->st_connection->spd.that.host_addr) - , (unsigned)sndst->st_connection->spd.that.host_port); - - memset(buffer, 0, sizeof(buffer)); - init_pbs(&pbs, buffer, sizeof(buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0; - if (icookie) - { - memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE); - } - if (rcookie) - { - memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE); - } - if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs)) - { - impossible(); - } - } - - /* HASH -- value to be filled later */ - if (encst) - { - pb_stream hash_pbs; - if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero( - encst->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH */ - } - - /* Notification Payload */ - { - pb_stream not_pbs; - struct isakmp_notification isan; - - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_type = type; - isan.isan_spisize = spisize; - isan.isan_protoid = protoid; - - if (!out_struct(&isan, &isakmp_notification_desc, &r_hdr_pbs, ¬_pbs) - || !out_raw(spi, spisize, ¬_pbs, "spi")) - { - impossible(); - } - close_output_pbs(¬_pbs); - } - - /* calculate hash value and patch into Hash Payload */ - if (encst) - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(encst->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, encst->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - if (encst) - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = encst->st_iv_len; - u_int new_iv_len = encst->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - { - impossible(); - } - memcpy(old_iv, encst->st_iv, old_iv_len); - memcpy(new_iv, encst->st_new_iv, new_iv_len); - - if (!IS_ISAKMP_SA_ESTABLISHED(encst->st_state)) - { - memcpy(encst->st_ph1_iv, encst->st_new_iv, encst->st_new_iv_len); - encst->st_ph1_iv_len = encst->st_new_iv_len; - } - init_phase2_iv(encst, &msgid); - if (!encrypt_message(&r_hdr_pbs, encst)) - { - impossible(); - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(encst->st_iv, old_iv, old_iv_len); - memcpy(encst->st_new_iv, new_iv, new_iv_len); - encst->st_iv_len = old_iv_len; - encst->st_new_iv_len = new_iv_len; - } - else - { - close_output_pbs(&r_hdr_pbs); - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = sndst->st_tpacket; - - sndst->st_tpacket = chunk_create(pbs.start, pbs_offset(&pbs)); - send_packet(sndst, "ISAKMP notify"); - sndst->st_tpacket = saved_tpacket; - } -} - -void send_notification_from_state(struct state *st, enum state_kind state, - u_int16_t type) -{ - struct state *p1st; - - passert(st); - - if (state == STATE_UNDEFINED) - state = st->st_state; - - if (IS_QUICK(state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if ((p1st == NULL) || (!IS_ISAKMP_SA_ESTABLISHED(p1st->st_state))) - { - loglog(RC_LOG_SERIOUS, - "no Phase1 state for Quick mode notification"); - return; - } - send_notification(st, type, p1st, generate_msgid(p1st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else if (IS_ISAKMP_ENCRYPTED(state) && st->st_enc_key.ptr != NULL) - { - send_notification(st, type, st, generate_msgid(st), - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } - else - { - /* no ISAKMP SA established - don't encrypt notification */ - send_notification(st, type, NULL, 0, - st->st_icookie, st->st_rcookie, NULL, 0, PROTO_ISAKMP); - } -} - -void send_notification_from_md(struct msg_digest *md, u_int16_t type) -{ - /** - * Create a dummy state to be able to use send_packet in - * send_notification - * - * we need to set: - * st_connection->that.host_addr - * st_connection->that.host_port - * st_connection->interface - */ - struct state st; - connection_t cnx; - - passert(md); - - memset(&st, 0, sizeof(st)); - memset(&cnx, 0, sizeof(cnx)); - st.st_connection = &cnx; - cnx.spd.that.host_addr = md->sender; - cnx.spd.that.host_port = md->sender_port; - cnx.interface = md->iface; - - send_notification(&st, type, NULL, 0, - md->hdr.isa_icookie, md->hdr.isa_rcookie, NULL, 0, PROTO_ISAKMP); -} - -/* Send a Delete Notification to announce deletion of ISAKMP SA or - * inbound IPSEC SAs. Does nothing if no such SAs are being deleted. - * Delete Notifications cannot announce deletion of outbound IPSEC/ISAKMP SAs. - */ -void send_delete(struct state *st) -{ - pb_stream reply_pbs; - pb_stream r_hdr_pbs; - msgid_t msgid; - u_char buffer[8192]; - struct state *p1st; - ip_said said[EM_MAXRELSPIS]; - ip_said *ns = said; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool isakmp_sa = FALSE; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - p1st = find_phase1_state(st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - if (p1st == NULL) - { - DBG(DBG_CONTROL, DBG_log("no Phase 1 state for Delete")); - return; - } - - if (st->st_ah.present) - { - ns->spi = st->st_ah.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_AH; - ns++; - } - if (st->st_esp.present) - { - ns->spi = st->st_esp.our_spi; - ns->dst = st->st_connection->spd.this.host_addr; - ns->proto = PROTO_IPSEC_ESP; - ns++; - } - - passert(ns != said); /* there must be some SAs to delete */ - } - else if (IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - p1st = st; - isakmp_sa = TRUE; - } - else - { - return; /* nothing to do */ - } - - msgid = generate_msgid(p1st); - - zero(buffer); - init_pbs(&reply_pbs, buffer, sizeof(buffer), "delete msg"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, p1st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, p1st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply_pbs, &r_hdr_pbs)) - impossible(); - } - - /* HASH -- value to be filled later */ - { - pb_stream hash_pbs; - - if (!out_generic(ISAKMP_NEXT_D, &isakmp_hash_desc, &r_hdr_pbs, &hash_pbs)) - { - impossible(); - } - r_hashval = hash_pbs.cur; /* remember where to plant value */ - if (!out_zero(p1st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH(1)")) - { - impossible(); - } - close_output_pbs(&hash_pbs); - r_hash_start = r_hdr_pbs.cur; /* hash from after HASH(1) */ - } - - /* Delete Payloads */ - if (isakmp_sa) - { - pb_stream del_pbs; - struct isakmp_delete isad; - u_char isakmp_spi[2*COOKIE_SIZE]; - - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ISAKMP_NEXT_NONE; - isad.isad_spisize = (2 * COOKIE_SIZE); - isad.isad_protoid = PROTO_ISAKMP; - isad.isad_nospi = 1; - - memcpy(isakmp_spi, st->st_icookie, COOKIE_SIZE); - memcpy(isakmp_spi+COOKIE_SIZE, st->st_rcookie, COOKIE_SIZE); - - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&isakmp_spi, (2*COOKIE_SIZE), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - else - { - while (ns != said) - { - - pb_stream del_pbs; - struct isakmp_delete isad; - - ns--; - isad.isad_doi = ISAKMP_DOI_IPSEC; - isad.isad_np = ns == said? ISAKMP_NEXT_NONE : ISAKMP_NEXT_D; - isad.isad_spisize = sizeof(ipsec_spi_t); - isad.isad_protoid = ns->proto; - - isad.isad_nospi = 1; - if (!out_struct(&isad, &isakmp_delete_desc, &r_hdr_pbs, &del_pbs) - || !out_raw(&ns->spi, sizeof(ipsec_spi_t), &del_pbs, "delete payload")) - { - impossible(); - } - close_output_pbs(&del_pbs); - } - } - - /* calculate hash value and patch into Hash Payload */ - { - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, r_hdr_pbs.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(p1st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, p1st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH(1) computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - - prf->destroy(prf); - } - - /* Do a dance to avoid needing a new state object. - * We use the Phase 1 State. This is the one with right - * IV, for one thing. - * The tricky bits are: - * - we need to preserve (save/restore) st_iv (but not st_iv_new) - * - we need to preserve (save/restore) st_tpacket. - */ - { - u_char old_iv[MAX_DIGEST_LEN]; - chunk_t saved_tpacket = p1st->st_tpacket; - - memcpy(old_iv, p1st->st_iv, p1st->st_iv_len); - init_phase2_iv(p1st, &msgid); - - if (!encrypt_message(&r_hdr_pbs, p1st)) - { - impossible(); - } - p1st->st_tpacket = chunk_create(reply_pbs.start, pbs_offset(&reply_pbs)); - send_packet(p1st, "delete notify"); - p1st->st_tpacket = saved_tpacket; - - /* get back old IV for this state */ - memcpy(p1st->st_iv, old_iv, p1st->st_iv_len); - } -} - -void accept_delete(struct state *st, struct msg_digest *md, - struct payload_digest *p) -{ - struct isakmp_delete *d = &(p->payload.delete); - identification_t *this_id = NULL, *that_id = NULL; - ip_address peer_addr; - size_t sizespi; - int i; - - if (!md->encrypted) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: not encrypted"); - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* can't happen (if msg is encrypt), but just to be sure */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not established"); - return; - } - - if (d->isad_nospi == 0) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: no SPI"); - return; - } - - switch (d->isad_protoid) - { - case PROTO_ISAKMP: - sizespi = 2 * COOKIE_SIZE; - break; - case PROTO_IPSEC_AH: - case PROTO_IPSEC_ESP: - sizespi = sizeof(ipsec_spi_t); - break; - case PROTO_IPCOMP: - /* nothing interesting to delete */ - return; - default: - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: unknown Protocol ID (%s)" - , enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (d->isad_spisize != sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: bad SPI size (%d) for %s" - , d->isad_spisize, enum_show(&protocol_names, d->isad_protoid)); - return; - } - - if (pbs_left(&p->pbs) != d->isad_nospi * sizespi) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: invalid payload size"); - return; - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - struct end *this = &st->st_connection->spd.this; - struct end *that = &st->st_connection->spd.that; - this_id = this->id->clone(this->id); - that_id = that->id->clone(that->id); - peer_addr = st->st_connection->spd.that.host_addr; - } - - for (i = 0; i < d->isad_nospi; i++) - { - u_char *spi = p->pbs.cur + (i * sizespi); - - if (d->isad_protoid == PROTO_ISAKMP) - { - /** - * ISAKMP - */ - struct state *dst = find_state(spi /*iCookie*/ - , spi+COOKIE_SIZE /*rCookie*/ - , &peer_addr - , MAINMODE_MSGID); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA not found (maybe expired)"); - } - else if (! this_id->equals(this_id, dst->st_connection->spd.this.id) || - ! that_id->equals(that_id, dst->st_connection->spd.that.id)) - { - /* we've not authenticated the relevant identities */ - loglog(RC_LOG_SERIOUS, "ignoring Delete SA payload: " - "ISAKMP SA used to convey Delete has different IDs from ISAKMP SA it deletes"); - } - else - { - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(dst->st_connection); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "deleting ISAKMP State #%lu", dst->st_serialno); - delete_state(dst); - set_cur_connection(oldc); - } - } - else - { - /** - * IPSEC (ESP/AH) - */ - bool bogus; - struct state *dst = find_phase2_state_to_delete(st - , d->isad_protoid - , *(ipsec_spi_t *)spi /* network order */ - , &bogus); - - if (dst == NULL) - { - loglog(RC_LOG_SERIOUS - , "ignoring Delete SA payload: %s SA(0x%08lx) not found (%s)" - , enum_show(&protocol_names, d->isad_protoid) - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , bogus ? "our SPI - bogus implementation" : "maybe expired"); - } - else - { - connection_t *rc = dst->st_connection; - connection_t *oldc; - - oldc = cur_connection; - set_cur_connection(rc); - - if (nat_traversal_enabled) - { - nat_traversal_change_port_lookup(md, dst); - } - if (rc->newest_ipsec_sa == dst->st_serialno - && (rc->policy & POLICY_UP)) - { - /* Last IPSec SA for a permanent connection that we - * have initiated. Replace it in a few seconds. - * - * Useful if the other peer is rebooting. - */ -#define DELETE_SA_DELAY EVENT_RETRANSMIT_DELAY_0 - if (dst->st_event != NULL - && dst->st_event->ev_type == EVENT_SA_REPLACE - && dst->st_event->ev_time <= DELETE_SA_DELAY + now()) - { - /* Patch from Angus Lees to ignore retransmited - * Delete SA. - */ - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "already replacing IPSEC State #%lu in %d seconds" - , dst->st_serialno, (int)(dst->st_event->ev_time - now())); - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA payload: " - "replace IPSEC State #%lu in %d seconds" - , dst->st_serialno, DELETE_SA_DELAY); - dst->st_margin = DELETE_SA_DELAY; - delete_event(dst); - event_schedule(EVENT_SA_REPLACE, DELETE_SA_DELAY, dst); - } - } - else - { - loglog(RC_LOG_SERIOUS, "received Delete SA(0x%08lx) payload: " - "deleting IPSEC State #%lu" - , (unsigned long)ntohl((unsigned long)*(ipsec_spi_t *)spi) - , dst->st_serialno); - delete_state(dst); - } - - /* reset connection */ - set_cur_connection(oldc); - } - } - } - - if (d->isad_protoid == PROTO_ISAKMP) - { - this_id->destroy(this_id); - that_id->destroy(that_id); - } -} - -/* The whole message must be a multiple of 4 octets. - * I'm not sure where this is spelled out, but look at - * rfc2408 3.6 Transform Payload. - * Note: it talks about 4 BYTE boundaries! - */ -void close_message(pb_stream *pbs) -{ - size_t padding = pad_up(pbs_offset(pbs), 4); - - if (padding != 0) - { - (void) out_zero(padding, pbs, "message padding"); - } - close_output_pbs(pbs); -} - -/* Initiate an Oakley Main Mode exchange. - * --> HDR;SA - * Note: this is not called from demux.c - */ -static stf_status -main_outI1(int whack_sock, connection_t *c, struct state *predecessor - , lset_t policy, unsigned long try) -{ - struct state *st = new_state(); - pb_stream reply; /* not actually a reply, but you know what I mean */ - pb_stream rbody; - int vids_to_send = 0; - - /* set up new state */ - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy & ~POLICY_IPSEC_MASK; - st->st_whack_sock = whack_sock; - st->st_try = try; - st->st_state = STATE_MAIN_I1; - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - - /* always send DPD Vendor ID */ - vids_to_send++; - - if (nat_traversal_enabled) - { - vids_to_send++; - } - - get_cookie(TRUE, st->st_icookie, COOKIE_SIZE, &c->spd.that.host_addr); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - if (HAS_IPSEC_POLICY(policy)) - { - add_pending(dup_any(whack_sock), st, c, policy, 1 - , predecessor == NULL? SOS_NOBODY : predecessor->st_serialno); - } - if (predecessor == NULL) - { - plog("initiating Main Mode"); - } - else - { - plog("initiating Main Mode to replace #%lu", predecessor->st_serialno); - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_SA; - hdr.isa_xchg = ISAKMP_XCHG_IDPROT; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - /* R-cookie, flags and MessageID are left zero */ - - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* SA out */ - { - u_char *sa_start = rbody.cur; - - if (!out_sa(&rbody, &oakley_sadb, st, TRUE - , vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save initiator SA for later HASH */ - passert(st->st_p1isa.ptr == NULL); /* no leak! (MUST be first time) */ - st->st_p1isa = chunk_create(sa_start, rbody.cur - sa_start); - st->st_p1isa = chunk_clone(st->st_p1isa); - } - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_STRONGSWAN)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_CISCO_UNITY)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - /* if we have an OpenPGP certificate we assume an - * OpenPGP peer and have to send the Vendor ID - */ - if (c->spd.this.cert && - c->spd.this.cert->cert->get_type(c->spd.this.cert->cert) == CERT_GPG) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_OPENPGP)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_XAUTH)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody, VID_MISC_DPD)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - if (nat_traversal_enabled) - { - /* Add supported NAT-Traversal VID */ - if (!nat_traversal_add_vid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - close_message(&rbody); - close_output_pbs(&reply); - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - - send_packet(st, "main_outI1"); - - /* Set up a retransmission event, half a minute henceforth */ - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (predecessor != NULL) - { - update_pending(predecessor, st); - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate, replacing #%lu" - , enum_name(&state_names, st->st_state) - , predecessor->st_serialno); - } - else - { - whack_log(RC_NEW_STATE + STATE_MAIN_I1 - , "%s: initiate", enum_name(&state_names, st->st_state)); - } - reset_cur_state(); - return STF_OK; -} - -void ipsecdoi_initiate(int whack_sock, connection_t *c, lset_t policy, - unsigned long try, so_serial_t replacing) -{ - /* If there's already an ISAKMP SA established, use that and - * go directly to Quick Mode. We are even willing to use one - * that is still being negotiated, but only if we are the Initiator - * (thus we can be sure that the IDs are not going to change; - * other issues around intent might matter). - * Note: there is no way to initiate with a Road Warrior. - */ - struct state *st = find_phase1_state(c - , ISAKMP_SA_ESTABLISHED_STATES | PHASE1_INITIATOR_STATES); - - if (st == NULL) - { - (void) main_outI1(whack_sock, c, NULL, policy, try); - } - else if (HAS_IPSEC_POLICY(policy)) - { - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - /* leave our Phase 2 negotiation pending */ - add_pending(whack_sock, st, c, policy, try, replacing); - } - else - { - /* ??? we assume that peer_nexthop_sin isn't important: - * we already have it from when we negotiated the ISAKMP SA! - * It isn't clear what to do with the error return. - */ - (void) quick_outI1(whack_sock, st, c, policy, try, replacing); - } - } - else - { - close_any(whack_sock); - } -} - -/* Replace SA with a fresh one that is similar - * - * Shares some logic with ipsecdoi_initiate, but not the same! - * - we must not reuse the ISAKMP SA if we are trying to replace it! - * - if trying to replace IPSEC SA, use ipsecdoi_initiate to build - * ISAKMP SA if needed. - * - duplicate whack fd, if live. - * Does not delete the old state -- someone else will do that. - */ -void ipsecdoi_replace(struct state *st, unsigned long try) -{ - int whack_sock = dup_any(st->st_whack_sock); - lset_t policy = st->st_policy; - - if (IS_PHASE1(st->st_state)) - { - passert(!HAS_IPSEC_POLICY(policy)); - (void) main_outI1(whack_sock, st->st_connection, st, policy, try); - } - else - { - /* Add features of actual old state to policy. This ensures - * that rekeying doesn't downgrade security. I admit that - * this doesn't capture everything. - */ - if (st->st_pfs_group != NULL) - policy |= POLICY_PFS; - if (st->st_ah.present) - { - policy |= POLICY_AUTHENTICATE; - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_esp.present && st->st_esp.attrs.transid != ESP_NULL) - { - policy |= POLICY_ENCRYPT; - if (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - if (st->st_ipcomp.present) - { - policy |= POLICY_COMPRESS; - if (st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - policy |= POLICY_TUNNEL; - } - passert(HAS_IPSEC_POLICY(policy)); - ipsecdoi_initiate(whack_sock, st->st_connection, policy, try - , st->st_serialno); - } -} - -/* SKEYID for preshared keys. - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool skeyid_preshared(struct state *st) -{ - const chunk_t *pss = get_preshared_secret(st->st_connection); - - if (pss == NULL) - { - loglog(RC_LOG_SERIOUS, "preshared secret disappeared!"); - return FALSE; - } - else - { - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - prf->set_key(prf, *pss); - prf->allocate_bytes(prf, st->st_ni, NULL); - prf->allocate_bytes(prf, st->st_nr, &st->st_skeyid); - prf->destroy(prf); - return TRUE; - } -} - -static bool skeyid_digisig(struct state *st) -{ - chunk_t nir; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - if (prf == NULL) - { - loglog(RC_LOG_SERIOUS, "%N not available to compute skeyid", - pseudo_random_function_names, prf_alg); - return FALSE; - } - free(st->st_skeyid.ptr); - nir = chunk_cat("cc", st->st_ni, st->st_nr); - prf->set_key(prf, nir); - prf->allocate_bytes(prf, st->st_shared, &st->st_skeyid); - prf->destroy(prf); - free(nir.ptr); - return TRUE; -} - -/* Generate the SKEYID_* and new IV - * See draft-ietf-ipsec-ike-01.txt 4.1 - */ -static bool generate_skeyids_iv(struct state *st) -{ - /* Generate the SKEYID */ - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - if (!skeyid_preshared(st)) - { - return FALSE; - } - break; - - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - if (!skeyid_digisig(st)) - { - return FALSE; - } - break; - - case OAKLEY_DSS_SIG: - /* XXX */ - - case OAKLEY_RSA_ENC: - case OAKLEY_RSA_ENC_REV: - case OAKLEY_ELGAMAL_ENC: - case OAKLEY_ELGAMAL_ENC_REV: - /* XXX */ - - default: - bad_case(st->st_oakley.auth); - } - - /* generate SKEYID_* from SKEYID */ - { - chunk_t seed_skeyid_d = chunk_from_chars(0x00); - chunk_t seed_skeyid_a = chunk_from_chars(0x01); - chunk_t seed_skeyid_e = chunk_from_chars(0x02); - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - /* SKEYID_D */ - free(st->st_skeyid_d.ptr); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_d, &st->st_skeyid_d); - - /* SKEYID_A */ - free(st->st_skeyid_a.ptr); - prf->allocate_bytes(prf, st->st_skeyid_d, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_a, &st->st_skeyid_a); - - /* SKEYID_E */ - free(st->st_skeyid_e.ptr); - prf->allocate_bytes(prf, st->st_skeyid_a, NULL); - prf->allocate_bytes(prf, st->st_shared, NULL); - prf->allocate_bytes(prf, icookie, NULL); - prf->allocate_bytes(prf, rcookie, NULL); - prf->allocate_bytes(prf, seed_skeyid_e, &st->st_skeyid_e); - - prf->destroy(prf); - } - - /* generate IV */ - { - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - DBG(DBG_CRYPT, - DBG_dump_chunk("DH_i:", st->st_gi); - DBG_dump_chunk("DH_r:", st->st_gr); - ); - - hasher->get_hash(hasher, st->st_gi, NULL); - hasher->get_hash(hasher, st->st_gr, st->st_new_iv); - hasher->destroy(hasher); - } - - /* Oakley Keying Material - * Derived from Skeyid_e: if it is not big enough, generate more - * using the PRF. - * See RFC 2409 "IKE" Appendix B - */ - { - size_t keysize = st->st_oakley.enckeylen/BITS_PER_BYTE; - - /* free any existing key */ - free(st->st_enc_key.ptr); - - if (keysize > st->st_skeyid_e.len) - { - u_char keytemp[MAX_OAKLEY_KEY_LEN + MAX_DIGEST_LEN]; - chunk_t seed = chunk_from_chars(0x00); - size_t prf_block_size, i; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_e); - prf_block_size = prf->get_block_size(prf); - - for (i = 0;;) - { - prf->get_bytes(prf, seed, &keytemp[i]); - i += prf_block_size; - if (i >= keysize) - { - break; - } - seed = chunk_create(&keytemp[i-prf_block_size], prf_block_size); - } - prf->destroy(prf); - st->st_enc_key = chunk_create(keytemp, keysize); - } - else - { - st->st_enc_key = chunk_create(st->st_skeyid_e.ptr, keysize); - } - st->st_enc_key = chunk_clone(st->st_enc_key); - } - - DBG(DBG_CRYPT, - DBG_dump_chunk("Skeyid: ", st->st_skeyid); - DBG_dump_chunk("Skeyid_d:", st->st_skeyid_d); - DBG_dump_chunk("Skeyid_a:", st->st_skeyid_a); - DBG_dump_chunk("Skeyid_e:", st->st_skeyid_e); - DBG_dump_chunk("enc key:", st->st_enc_key); - DBG_dump("IV:", st->st_new_iv, st->st_new_iv_len)); - return TRUE; -} - -/* Generate HASH_I or HASH_R for ISAKMP Phase I. - * This will *not* generate other hash payloads (eg. Phase II or Quick Mode, - * New Group Mode, or ISAKMP Informational Exchanges). - * If the hashi argument is TRUE, generate HASH_I; if FALSE generate HASH_R. - * If hashus argument is TRUE, we're generating a hash for our end. - * See RFC2409 IKE 5. - */ - static void main_mode_hash(struct state *st, chunk_t *hash, bool hashi, - const pb_stream *idpl) -{ - chunk_t icookie = { st->st_icookie, COOKIE_SIZE }; - chunk_t rcookie = { st->st_rcookie, COOKIE_SIZE }; - chunk_t sa_body = { st->st_p1isa.ptr + sizeof(struct isakmp_generic), - st->st_p1isa.len - sizeof(struct isakmp_generic) }; - chunk_t id_body = { idpl->start + sizeof(struct isakmp_generic), - pbs_offset(idpl) - sizeof(struct isakmp_generic) }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - switch (st->st_oakley.auth) - { - case OAKLEY_ECDSA_256: - prf_alg = PRF_HMAC_SHA2_256; - break; - case OAKLEY_ECDSA_384: - prf_alg = PRF_HMAC_SHA2_384; - break; - case OAKLEY_ECDSA_521: - prf_alg = PRF_HMAC_SHA2_512; - break; - default: - prf_alg = oakley_to_prf(st->st_oakley.hash); - } - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid); - - if (hashi) - { - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, icookie, NULL); - prf->get_bytes(prf, rcookie, NULL); - } - else - { - prf->get_bytes(prf, st->st_gr, NULL); - prf->get_bytes(prf, st->st_gi, NULL); - prf->get_bytes(prf, rcookie, NULL); - prf->get_bytes(prf, icookie, NULL); - } - - DBG(DBG_CRYPT, - DBG_log("hashing %u bytes of SA", sa_body.len) - ) - prf->get_bytes(prf, sa_body, NULL); - - /* Hash identification payload, without generic payload header. - * We used to reconstruct ID Payload for this purpose, but now - * we use the bytes as they appear on the wire to avoid - * "spelling problems". - */ - prf->get_bytes(prf, id_body, hash->ptr); - hash->len = prf->get_block_size(prf); - prf->destroy(prf); -} - -/* Create a public key signature of a hash. - * Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2. - * Use PKCS#1 version 1.5 encryption of hash (called - * RSAES-PKCS1-V1_5) in PKCS#2. - */ -static size_t sign_hash(signature_scheme_t scheme, connection_t *c, - u_char sig_val[RSA_MAX_OCTETS], chunk_t hash) -{ - size_t sz = 0; - smartcard_t *sc = c->spd.this.sc; - - if (sc == NULL) /* no smartcard */ - { - chunk_t sig; - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - return 0; /* failure: no key to use */ - } - if (!private->sign(private, scheme, hash, &sig)) - { - return 0; - } - memcpy(sig_val, sig.ptr, sig.len); - sz = sig.len; - free(sig.ptr); - } - else if (sc->valid) /* if valid pin then sign hash on the smartcard */ - { - lock_certs_and_keys("sign_hash"); - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - sz = scx_get_keylength(sc); - if (sz == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - unlock_certs_and_keys("sign_hash"); - return 0; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with private key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - sz = scx_sign_hash(sc, hash.ptr, hash.len, sig_val, sz) ? sz : 0; - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - unlock_certs_and_keys("sign_hash"); - } - return sz; -} - -/* Check signature against all public keys we can find. - * If we need keys from DNS KEY records, and they haven't been fetched, - * return STF_SUSPEND to ask for asynch DNS lookup. - * - * Note: parameter keys_from_dns contains results of DNS lookup for key - * or is NULL indicating lookup not yet tried. - * - * take_a_crack is a helper function. Mostly forensic. - * If only we had coroutines. - */ -struct tac_state { - struct state *st; - chunk_t hash; - chunk_t sig; - int tried_cnt; /* number of keys tried */ -}; - -static bool take_a_crack(struct tac_state *s, pubkey_t *kr) -{ - public_key_t *pub_key = kr->public_key; - chunk_t keyid = chunk_empty; - signature_scheme_t scheme; - - s->tried_cnt++; - scheme = oakley_to_signature_scheme(s->st->st_oakley.auth); - pub_key->get_fingerprint(pub_key, KEYID_PUBKEY_INFO_SHA1, &keyid); - - if (pub_key->verify(pub_key, scheme, s->hash, s->sig)) - { - DBG(DBG_CRYPT | DBG_CONTROL, - DBG_log("%s check passed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - unreference_key(&s->st->st_peer_pubkey); - s->st->st_peer_pubkey = reference_key(kr); - return TRUE; - } - else - { - DBG(DBG_CRYPT, - DBG_log("%s check failed with keyid %#B", - enum_show(&oakley_auth_names, s->st->st_oakley.auth), &keyid) - ) - return FALSE; - } -} - -static stf_status check_signature(key_type_t key_type, identification_t* peer, - struct state *st, chunk_t hash, - const pb_stream *sig_pbs, -#ifdef USE_KEYRR - const pubkey_list_t *keys_from_dns, -#endif /* USE_KEYRR */ - const struct gw_info *gateways_from_dns) -{ - const connection_t *c = st->st_connection; - struct tac_state s; - - s.st = st; - s.hash = hash; - s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs)); - s.tried_cnt = 0; - - /* try all gateway records hung off c */ - if (c->policy & POLICY_OPPO) - { - struct gw_info *gw; - - for (gw = c->gw_info; gw != NULL; gw = gw->next) - { - /* only consider entries that have a key and are for our peer */ - if (gw->gw_key_present && - gw->gw_id->equals(gw->gw_id, c->spd.that.id) && - take_a_crack(&s, gw->key)) - { - return STF_OK; - } - } - } - - /* try all appropriate Public keys */ - { - pubkey_list_t *p, **pp; - - pp = &pubkeys; - - for (p = pubkeys; p != NULL; p = *pp) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == key_type && peer->equals(peer, key->id)) - { - time_t now = time(NULL); - - /* check if found public key has expired */ - if (key->until_time != UNDEFINED_TIME && key->until_time < now) - { - loglog(RC_LOG_SERIOUS, - "cached public key has expired and has been deleted"); - *pp = free_public_keyentry(p); - continue; /* continue with next public key */ - } - if (take_a_crack(&s, key)) - { - return STF_OK; - } - } - pp = &p->next; - } - } - - /* if no key was found and that side of connection is - * key_from_DNS_on_demand then go search DNS for keys for peer. - */ - if (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand) - { - if (gateways_from_dns != NULL) - { - /* TXT keys */ - const struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - if (gwp->gw_key_present && take_a_crack(&s, gwp->key)) - { - return STF_OK; - } - } - } -#ifdef USE_KEYRR - else if (keys_from_dns != NULL) - { - /* KEY keys */ - const pubkey_list_t *kr; - - for (kr = keys_from_dns; kr != NULL; kr = kr->next) - { - if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key)) - { - return STF_OK; - } - } - } -#endif /* USE_KEYRR */ - else - { - /* nothing yet: ask for asynch DNS lookup */ - return STF_SUSPEND; - } - } - - /* no acceptable key was found: diagnose */ - { - if (s.tried_cnt == 0) - { - loglog(RC_LOG_SERIOUS, "no public key known for '%Y'", peer); - } - else if (s.tried_cnt == 1) - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - " wrong key?; tried %d", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("public key for '%Y' failed: " - "decrypted SIG payload into a malformed ECB", peer) - ) - } - else - { - loglog(RC_LOG_SERIOUS, "signature check for '%Y' failed: " - "tried %d keys but none worked.", peer, s.tried_cnt); - DBG(DBG_CONTROL, - DBG_log("all %d public keys for '%Y' failed: " - "best decrypted SIG payload into a malformed ECB", - s.tried_cnt, peer) - ) - } - return STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } -} - -static notification_t accept_nonce(struct msg_digest *md, chunk_t *dest, - const char *name) -{ - pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs; - size_t len = pbs_left(nonce_pbs); - - if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) - { - loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" - , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); - return ISAKMP_PAYLOAD_MALFORMED; /* ??? */ - } - free(dest->ptr); - *dest = chunk_create(nonce_pbs->cur, len); - *dest = chunk_clone(*dest); - return ISAKMP_NOTHING_WRONG; -} - -/* encrypt message, sans fixed part of header - * IV is fetched from st->st_new_iv and stored into st->st_iv. - * The theory is that there will be no "backing out", so we commit to IV. - * We also close the pbs. - */ -bool encrypt_message(pb_stream *pbs, struct state *st) -{ - u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); - size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); - chunk_t data, iv; - char *new_iv; - size_t crypter_block_size, crypter_iv_size; - encryption_algorithm_t enc_alg; - crypter_t *crypter; - - DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); - enc_alg = oakley_to_encryption_algorithm(st->st_oakley.encrypt); - crypter = lib->crypto->create_crypter(lib->crypto, enc_alg, st->st_enc_key.len); - crypter_block_size = crypter->get_block_size(crypter); - crypter_iv_size = crypter->get_iv_size(crypter); - - /* Pad up to multiple of encryption blocksize. - * See the description associated with the definition of - * struct isakmp_hdr in packet.h. - */ - { - size_t padding = pad_up(enc_len, crypter_block_size); - - if (padding != 0) - { - if (!out_zero(padding, pbs, "encryption padding")) - return FALSE; - enc_len += padding; - } - } - - DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); - data = chunk_create(enc_start, enc_len); - - /* form iv by truncation */ - st->st_new_iv_len = crypter_iv_size; - iv = chunk_create(st->st_new_iv, st->st_new_iv_len); - - crypter->set_key(crypter, st->st_enc_key); - crypter->encrypt(crypter, data, iv, NULL); - crypter->destroy(crypter); - - new_iv = data.ptr + data.len - crypter_iv_size; - memcpy(st->st_new_iv, new_iv, crypter_iv_size); - update_iv(st); - DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); - close_message(pbs); - return TRUE; -} - -/* Compute HASH(1), HASH(2) of Quick Mode. - * HASH(1) is part of Quick I1 message. - * HASH(2) is part of Quick R1 message. - * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 - * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) - */ -static size_t quick_mode_hash12(u_char *dest, u_char *start, u_char *roof, - const struct state *st, const msgid_t *msgid, - bool hash2) -{ - chunk_t msgid_chunk = chunk_from_thing(*msgid); - chunk_t msg_chunk = { start, roof - start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - if (hash2) - { - prf->get_bytes(prf, st->st_ni, NULL); /* include Ni_b in the hash */ - } - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("HASH(%d) computed:", hash2 + 1); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - -/* Compute HASH(3) in Quick Mode (part of Quick I2 message). - * Used by: quick_inR1_outI2, quick_inI2 - * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. - * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the - * Message ID and Nonces. This is a mistake. - */ -static size_t quick_mode_hash3(u_char *dest, struct state *st) -{ - chunk_t seed_chunk = chunk_from_chars(0x00); - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - pseudo_random_function_t prf_alg; - prf_t *prf; - size_t prf_block_size; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, seed_chunk, NULL ); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, prf_block_size); - return prf_block_size; -} - -/* Compute Phase 2 IV. - * Uses Phase 1 IV from st_iv; puts result in st_new_iv. - */ -void init_phase2_iv(struct state *st, const msgid_t *msgid) -{ - chunk_t iv_chunk = { st->st_ph1_iv, st->st_ph1_iv_len }; - chunk_t msgid_chunk = chunk_from_thing(*msgid); - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = oakley_to_hash_algorithm(st->st_oakley.hash); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - - DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:", - st->st_ph1_iv, st->st_ph1_iv_len); - - st->st_new_iv_len = hasher->get_hash_size(hasher); - passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); - - hasher->get_hash(hasher, iv_chunk, NULL); - hasher->get_hash(hasher, msgid_chunk, st->st_new_iv); - hasher->destroy(hasher); - - DBG_cond_dump(DBG_CRYPT, "computed Phase 2 IV:", - st->st_new_iv, st->st_new_iv_len); -} - -/* Initiate quick mode. - * --> HDR*, HASH(1), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Note: this is not called from demux.c - */ - -static bool emit_subnet_id(ip_subnet *net, u_int8_t np, u_int8_t protoid, - u_int16_t port, pb_stream *outs) -{ - struct isakmp_ipsec_id id; - pb_stream id_pbs; - ip_address ta; - const unsigned char *tbp; - size_t tal; - - id.isaiid_np = np; - id.isaiid_idtype = subnetishost(net) - ? aftoinfo(subnettypeof(net))->id_addr - : aftoinfo(subnettypeof(net))->id_subnet; - id.isaiid_protoid = protoid; - id.isaiid_port = port; - - if (!out_struct(&id, &isakmp_ipsec_identification_desc, outs, &id_pbs)) - { - return FALSE; - } - networkof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client network")) - { - return FALSE; - } - if (!subnetishost(net)) - { - maskof(net, &ta); - tal = addrbytesptr(&ta, &tbp); - if (!out_raw(tbp, tal, &id_pbs, "client mask")) - { - return FALSE; - } - } - close_output_pbs(&id_pbs); - return TRUE; -} - -stf_status quick_outI1(int whack_sock, struct state *isakmp_sa, - connection_t *c, lset_t policy, unsigned long try, - so_serial_t replacing) -{ - struct state *st = duplicate_state(isakmp_sa); - pb_stream reply; /* not really a reply */ - pb_stream rbody; - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - bool has_client = c->spd.this.has_client || c->spd.that.has_client || - c->spd.this.protocol || c->spd.that.protocol || - c->spd.this.port || c->spd.that.port; - bool send_natoa = FALSE; - u_int8_t np = ISAKMP_NEXT_NONE; - connection_t *ph1_c = isakmp_sa->st_connection; - - if (c->spd.this.modecfg && !c->spd.this.has_client && - c->spd.this.host_srcip->is_anyaddr(c->spd.this.host_srcip)) - { - host_t * ph1_srcip = ph1_c->spd.this.host_srcip; - - if (ph1_c->spd.this.modecfg && !ph1_srcip->is_anyaddr(ph1_srcip)) - { - c->spd.this.host_srcip->destroy(c->spd.this.host_srcip); - c->spd.this.host_srcip = ph1_srcip->clone(ph1_srcip); - c->spd.this.client = ph1_c->spd.this.client; - c->spd.this.has_client = TRUE; - plog("inheriting virtual IP source address %H from ModeCfg", ph1_srcip); - } - } - - if (ph1_c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - ph1_c->xauth_identity && !c->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", ph1_c->xauth_identity) - ) - c->xauth_identity = ph1_c->xauth_identity->clone(ph1_c->xauth_identity); - } - - st->st_whack_sock = whack_sock; - st->st_connection = c; - set_cur_state(st); /* we must reset before exit */ - st->st_policy = policy; - st->st_try = try; - - st->st_myuserprotoid = c->spd.this.protocol; - st->st_peeruserprotoid = c->spd.that.protocol; - st->st_myuserport = c->spd.this.port; - st->st_peeruserport = c->spd.that.port; - - st->st_msgid = generate_msgid(isakmp_sa); - st->st_state = STATE_QUICK_I1; - - insert_state(st); /* needs cookies, connection, and msgid */ - - if (replacing == SOS_NOBODY) - { - plog("initiating Quick Mode %s {using isakmp#%lu}", - prettypolicy(policy), isakmp_sa->st_serialno); - } - else - { - plog("initiating Quick Mode %s to replace #%lu {using isakmp#%lu}", - prettypolicy(policy), replacing, isakmp_sa->st_serialno); - } - if (isakmp_sa->nat_traversal & NAT_T_DETECTED) - { - /* Duplicate nat_traversal status in new state */ - st->nat_traversal = isakmp_sa->nat_traversal; - - if (isakmp_sa->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - { - has_client = TRUE; - } - nat_traversal_change_port_lookup(NULL, st); - } - else - { - st->nat_traversal = 0; - } - - /* are we going to send a NAT-OA payload? */ - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && !(st->st_policy & POLICY_TUNNEL) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME))) - { - send_natoa = TRUE; - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATOA_RFC : ISAKMP_NEXT_NATOA_DRAFTS; - } - - /* set up reply */ - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "reply packet"); - - /* HDR* out */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_QUICK; - hdr.isa_msgid = st->st_msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* HASH(1) -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_SA); - - /* SA out */ - - /* - * See if pfs_group has been specified for this conn, - * if not, fallback to old use-same-as-P1 behaviour - */ -#ifndef NO_IKE_ALG - if (st->st_connection) - { - st->st_pfs_group = ike_alg_pfsgroup(st->st_connection, policy); - } - if (!st->st_pfs_group) -#endif - /* If PFS specified, use the same group as during Phase 1: - * since no negotiation is possible, we pick one that is - * very likely supported. - */ - st->st_pfs_group = policy & POLICY_PFS? isakmp_sa->st_oakley.group : NULL; - - /* Emit SA payload based on a subset of the policy bits. - * POLICY_COMPRESS is considered iff we can do IPcomp. - */ - { - lset_t pm = POLICY_ENCRYPT | POLICY_AUTHENTICATE; - - if (can_do_IPcomp) - { - pm |= POLICY_COMPRESS; - } - if (!out_sa(&rbody, - &ipsec_sadb[(st->st_policy & pm) >> POLICY_IPSEC_SHIFT], - st, FALSE, ISAKMP_NEXT_NONCE)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &rbody - , policy & POLICY_PFS? ISAKMP_NEXT_KE : has_client? ISAKMP_NEXT_ID : np - , "Ni")) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gi, st->st_pfs_group - , &rbody, has_client? ISAKMP_NEXT_ID : np)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* [ IDci, IDcr ] out */ - if (has_client) - { - /* IDci (we are initiator), then IDcr (peer is responder) */ - if (!emit_subnet_id(&c->spd.this.client - , ISAKMP_NEXT_ID, st->st_myuserprotoid, st->st_myuserport, &rbody) - || !emit_subnet_id(&c->spd.that.client - , np, st->st_peeruserprotoid, st->st_peeruserport, &rbody)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* Send NAT-OA if our address is NATed */ - if (send_natoa) - { - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - } - - /* finish computing HASH(1), inserting it in output */ - (void) quick_mode_hash12(r_hashval, r_hash_start, rbody.cur - , st, &st->st_msgid, FALSE); - - /* encrypt message, except for fixed part of header */ - - init_phase2_iv(isakmp_sa, &st->st_msgid); - st->st_new_iv_len = isakmp_sa->st_new_iv_len; - memcpy(st->st_new_iv, isakmp_sa->st_new_iv, st->st_new_iv_len); - - if (!encrypt_message(&rbody, st)) - { - reset_cur_state(); - return STF_INTERNAL_ERROR; - } - - /* save packet, now that we know its size */ - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* send the packet */ - - send_packet(st, "quick_outI1"); - - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - - if (replacing == SOS_NOBODY) - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate" - , enum_name(&state_names, st->st_state)); - } - else - { - whack_log(RC_NEW_STATE + STATE_QUICK_I1 - , "%s: initiate to replace #%lu" - , enum_name(&state_names, st->st_state) - , replacing); - } - reset_cur_state(); - return STF_OK; -} - - -/* - * Decode the CERT payload of Phase 1. - */ -static void decode_cert(struct msg_digest *md) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CERT]; p != NULL; p = p->next) - { - struct isakmp_cert *const cert = &p->payload.cert; - chunk_t blob; - time_t valid_until; - blob.ptr = p->pbs.cur; - blob.len = pbs_left(&p->pbs); - if (cert->isacert_type == CERT_X509_SIGNATURE) - { - cert_t x509cert = cert_empty; - - x509cert.cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, blob, - BUILD_END); - if (x509cert.cert) - { - if (verify_x509cert(&x509cert, strict_crl_policy, &valid_until)) - { - DBG(DBG_PARSING, - DBG_log("Public key validated") - ) - add_public_key_from_cert(&x509cert, valid_until, DAL_SIGNED); - } - else - { - plog("X.509 certificate rejected"); - } - x509cert.cert->destroy(x509cert.cert); - } - else - { - plog("Syntax error in X.509 certificate"); - } - } - else if (cert->isacert_type == CERT_PKCS7_WRAPPED_X509) - { - linked_list_t *certs = linked_list_create(); - - if (pkcs7_parse_signedData(blob, NULL, certs, NULL, NULL)) - { - store_x509certs(certs, strict_crl_policy); - } - else - { - plog("Syntax error in PKCS#7 wrapped X.509 certificates"); - } - certs->destroy_offset(certs, offsetof(certificate_t, destroy)); - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload", - enum_show(&cert_type_names, cert->isacert_type)); - DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob); - } - } -} - -/* - * Decode the CR payload of Phase 1. - */ -static void decode_cr(struct msg_digest *md, connection_t *c) -{ - struct payload_digest *p; - - for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) - { - struct isakmp_cr *const cr = &p->payload.cr; - chunk_t ca_name; - - ca_name.len = pbs_left(&p->pbs); - ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL; - - DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); - - if (cr->isacr_type == CERT_X509_SIGNATURE) - { - if (ca_name.len > 0) - { - identification_t *ca; - - if (!is_asn1(ca_name)) - { - continue; - } - if (c->requested_ca == NULL) - { - c->requested_ca = linked_list_create(); - } - ca = identification_create_from_encoding(ID_DER_ASN1_DN, ca_name); - c->requested_ca->insert_last(c->requested_ca, ca); - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: \"%Y\"", ca) - ) - } - else - { - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("requested CA: %%any") - ) - } - c->got_certrequest = TRUE; - } - else - { - loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", - enum_show(&cert_type_names, cr->isacr_type)); - } - } -} - -/* Decode the ID payload of Phase 1 (main_inI3_outR3 and main_inR3) - * Note: we may change connections as a result. - * We must be called before SIG or HASH are decoded since we - * may change the peer's public key or ID. - */ -static bool decode_peer_id(struct msg_digest *md, identification_t **peer) -{ - struct state *const st = md->st; - struct payload_digest *const id_pld = md->chain[ISAKMP_NEXT_ID]; - const pb_stream *const id_pbs = &id_pld->pbs; - struct isakmp_id *const id = &id_pld->payload.id; - chunk_t id_payload; - - /* I think that RFC2407 (IPSEC DOI) 4.6.2 is confused. - * It talks about the protocol ID and Port fields of the ID - * Payload, but they don't exist as such in Phase 1. - * We use more appropriate names. - * isaid_doi_specific_a is in place of Protocol ID. - * isaid_doi_specific_b is in place of Port. - * Besides, there is no good reason for allowing these to be - * other than 0 in Phase 1. - */ - if ((st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && id->isaid_doi_specific_a == IPPROTO_UDP - && (id->isaid_doi_specific_b == 0 || id->isaid_doi_specific_b == NAT_T_IKE_FLOAT_PORT)) - { - DBG_log("protocol/port in Phase 1 ID Payload is %d/%d. " - "accepted with port_floating NAT-T", - id->isaid_doi_specific_a, id->isaid_doi_specific_b); - } - else if (!(id->isaid_doi_specific_a == 0 && id->isaid_doi_specific_b == 0) - && !(id->isaid_doi_specific_a == IPPROTO_UDP && id->isaid_doi_specific_b == IKE_UDP_PORT)) - { - loglog(RC_LOG_SERIOUS, "protocol/port in Phase 1 ID Payload must be 0/0 or %d/%d" - " but are %d/%d" - , IPPROTO_UDP, IKE_UDP_PORT - , id->isaid_doi_specific_a, id->isaid_doi_specific_b); - return FALSE; - } - - id_payload = chunk_create(id_pbs->cur, pbs_left(id_pbs)); - - switch (id->isaid_idtype) - { - case ID_IPV4_ADDR: - if (id_payload.len != 4) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_IPV6_ADDR: - if (id_payload.len != 16) - { - loglog(RC_LOG_SERIOUS, "improper %s Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_USER_FQDN: - case ID_FQDN: - if (memchr(id_payload.ptr, '\0', id_payload.len) != NULL) - { - loglog(RC_LOG_SERIOUS, "%s Phase 1 ID payload contains " - "a NUL character", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - break; - case ID_KEY_ID: - case ID_DER_ASN1_DN: - break; - default: - /* XXX Could send notification back */ - loglog(RC_LOG_SERIOUS, "unacceptable identity type (%s) " - "in Phase 1 ID payload", - enum_show(&ident_names, id->isaid_idtype)); - return FALSE; - } - *peer = identification_create_from_encoding(id->isaid_idtype, id_payload); - - plog("Peer ID is %s: '%Y'", enum_show(&ident_names, id->isaid_idtype), - *peer); - - /* check for certificates */ - decode_cert(md); - return TRUE; -} - -/* Now that we've decoded the ID payload, let's see if we - * need to switch connections. - * We must not switch horses if we initiated: - * - if the initiation was explicit, we'd be ignoring user's intent - * - if opportunistic, we'll lose our HOLD info - */ -static bool switch_connection(struct msg_digest *md, identification_t *peer, - bool initiator) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - identification_t *peer_ca; - - peer_ca = st->st_peer_pubkey ? st->st_peer_pubkey->issuer : NULL; - if (peer_ca) - { - DBG(DBG_CONTROL, - DBG_log("peer CA: \"%Y\"", peer_ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer CA: %%none") - ) - } - - if (initiator) - { - int pathlen; - - if (!peer->equals(peer, c->spd.that.id)) - { - loglog(RC_LOG_SERIOUS, - "we require peer to have ID '%Y', but peer declares '%Y'", - c->spd.that.id, peer); - return FALSE; - } - - if (c->spd.that.ca) - { - DBG(DBG_CONTROL, - DBG_log("required CA: \"%s\"", c->spd.that.ca); - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("required CA: %%none"); - ) - } - - if (!trusted_ca(peer_ca, c->spd.that.ca, &pathlen)) - { - loglog(RC_LOG_SERIOUS - , "we don't accept the peer's CA"); - return FALSE; - } - } - else - { - connection_t *r; - - /* check for certificate requests */ - decode_cr(md, c); - - r = refine_host_connection(st, peer, peer_ca); - - /* delete the collected certificate requests */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - if (r == NULL) - { - loglog(RC_LOG_SERIOUS, "no suitable connection for peer '%Y'", peer); - return FALSE; - } - - if (r->spd.this.ca) - { - DBG(DBG_CONTROL, - DBG_log("offered CA: \"%Y\"", r->spd.this.ca) - ) - } - else - { - DBG(DBG_CONTROL, - DBG_log("offered CA: %%none") - ) - } - - if (r != c) - { - /* apparently, r is an improvement on c -- replace */ - - DBG(DBG_CONTROL - , DBG_log("switched from \"%s\" to \"%s\"", c->name, r->name)); - if (r->kind == CK_TEMPLATE) - { - /* instantiate it, filling in peer's ID */ - r = rw_instantiate(r, &c->spd.that.host_addr - , c->spd.that.host_port, NULL, peer); - } - - /* copy certificate request info */ - r->got_certrequest = c->got_certrequest; - - st->st_connection = r; /* kill reference to c */ - set_cur_connection(r); - connection_discard(c); - } - else if (c->spd.that.has_id_wildcards) - { - c->spd.that.id->destroy(c->spd.that.id); - c->spd.that.id = peer->clone(peer); - c->spd.that.has_id_wildcards = FALSE; - } - } - return TRUE; -} - -/* Decode the variable part of an ID packet (during Quick Mode). - * This is designed for packets that identify clients, not peers. - * Rejects 0.0.0.0/32 or IPv6 equivalent because - * (1) it is wrong and (2) we use this value for inband signalling. - */ -static bool decode_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - ip_subnet *net, const char *which) -{ - const struct af_info *afi = NULL; - - /* Note: the following may be a pointer into static memory - * that may be recycled, but only if the type is not known. - * That case is disposed of very early -- in the first switch. - */ - const char *idtypename = enum_show(&ident_names, id->isaiid_idtype); - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV4_ADDR_SUBNET: - case ID_IPV4_ADDR_RANGE: - afi = &af_inet4_info; - break; - case ID_IPV6_ADDR: - case ID_IPV6_ADDR_SUBNET: - case ID_IPV6_ADDR_RANGE: - afi = &af_inet6_info; - break; - case ID_FQDN: - return TRUE; - default: - /* XXX support more */ - loglog(RC_LOG_SERIOUS, "unsupported ID type %s" - , idtypename); - /* XXX Could send notification back */ - return FALSE; - } - - switch (id->isaiid_idtype) - { - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - { - ip_address temp_address; - err_t ugh; - - ugh = initaddr(id_pbs->cur, pbs_left(id_pbs), afi->af, &temp_address); - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s has wrong length in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - if (isanyaddr(&temp_address)) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s is invalid (%s) in Quick I1" - , which, idtypename, ip_str(&temp_address)); - /* XXX Could send notification back */ - return FALSE; - } - happy(addrtosubnet(&temp_address, net)); - DBG(DBG_PARSING | DBG_CONTROL - , DBG_log("%s is %s", which, ip_str(&temp_address))); - break; - } - - case ID_IPV4_ADDR_SUBNET: - case ID_IPV6_ADDR_SUBNET: - { - ip_address temp_address, temp_mask; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur - , afi->ia_sz, afi->af, &temp_address); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_mask); - } - if (ugh == NULL) - { - ugh = initsubnet(&temp_address, masktocount(&temp_mask) - , '0', net); - } - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s bad subnet in Quick I1 (%s)" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s", which, temp_buff); - }); - break; - } - - case ID_IPV4_ADDR_RANGE: - case ID_IPV6_ADDR_RANGE: - { - ip_address temp_address_from, temp_address_to; - err_t ugh; - - if (pbs_left(id_pbs) != 2 * afi->ia_sz) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s wrong length in Quick I1" - , which, idtypename); - /* XXX Could send notification back */ - return FALSE; - } - ugh = initaddr(id_pbs->cur, afi->ia_sz, afi->af, &temp_address_from); - if (ugh == NULL) - { - ugh = initaddr(id_pbs->cur + afi->ia_sz - , afi->ia_sz, afi->af, &temp_address_to); - } - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "%s ID payload %s malformed (%s) in Quick I1" - , which, idtypename, ugh); - /* XXX Could send notification back */ - return FALSE; - } - - ugh = rangetosubnet(&temp_address_from, &temp_address_to, net); - if (ugh == NULL && subnetisnone(net)) - { - ugh = "contains only anyaddr"; - } - if (ugh != NULL) - { - char temp_buff1[ADDRTOT_BUF], temp_buff2[ADDRTOT_BUF]; - - addrtot(&temp_address_from, 0, temp_buff1, sizeof(temp_buff1)); - addrtot(&temp_address_to, 0, temp_buff2, sizeof(temp_buff2)); - loglog(RC_LOG_SERIOUS, "%s ID payload in Quick I1, %s" - " %s - %s unacceptable: %s" - , which, idtypename, temp_buff1, temp_buff2, ugh); - return FALSE; - } - DBG(DBG_PARSING | DBG_CONTROL, - { - char temp_buff[SUBNETTOT_BUF]; - - subnettot(net, 0, temp_buff, sizeof(temp_buff)); - DBG_log("%s is subnet %s (received as range)" - , which, temp_buff); - }); - break; - } - } - - /* set the port selector */ - setportof(htons(id->isaiid_port), &net->addr); - - DBG(DBG_PARSING | DBG_CONTROL, - DBG_log("%s protocol/port is %d/%d", which, id->isaiid_protoid, id->isaiid_port) - ) - - return TRUE; -} - -/* like decode, but checks that what is received matches what was sent */ -static bool check_net_id(struct isakmp_ipsec_id *id, pb_stream *id_pbs, - u_int8_t *protoid, u_int16_t *port, ip_subnet *net, - const char *which) -{ - ip_subnet net_temp; - - if (!decode_net_id(id, id_pbs, &net_temp, which)) - { - return FALSE; - } - if (!samesubnet(net, &net_temp) - || *protoid != id->isaiid_protoid || *port != id->isaiid_port) - { - loglog(RC_LOG_SERIOUS, "%s ID returned doesn't match my proposal", which); - return FALSE; - } - return TRUE; -} - -/* - * look for the existence of a non-expiring preloaded public key - */ -static bool has_preloaded_public_key(struct state *st) -{ - connection_t *c = st->st_connection; - - /* do not consider rw connections since - * the peer's identity must be known - */ - if (c->kind == CK_PERMANENT) - { - pubkey_list_t *p; - - /* look for a matching RSA public key */ - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - - if (type == KEY_RSA && - c->spd.that.id->equals(c->spd.that.id, key->id) && - key->until_time == UNDEFINED_TIME) - { - /* found a preloaded public key */ - return TRUE; - } - } - } - return FALSE; -} - -/* Compute keying material for an SA - */ -static void compute_keymat_internal(struct state *st, u_int8_t protoid, - ipsec_spi_t spi, size_t needed_len, - u_char **keymat_out) -{ - size_t i = 0, prf_block_size, needed_space; - chunk_t protoid_chunk = chunk_from_thing(protoid); - chunk_t spi_chunk = chunk_from_thing(spi); - pseudo_random_function_t prf_alg = oakley_to_prf(st->st_oakley.hash); - prf_t *prf = lib->crypto->create_prf(lib->crypto, prf_alg); - - prf->set_key(prf, st->st_skeyid_d); - prf_block_size = prf->get_block_size(prf); - - /* Although only needed_len bytes are desired, we must round up to a - * multiple of prf_block_size so that the buffer isn't overrun */ - needed_space = needed_len + pad_up(needed_len, prf_block_size); - replace(*keymat_out, malloc(needed_space)); - - for (;;) - { - char *keymat_i = (*keymat_out) + i; - chunk_t keymat = { keymat_i, prf_block_size }; - - if (st->st_shared.ptr != NULL) - { /* PFS: include the g^xy */ - prf->get_bytes(prf, st->st_shared, NULL); - } - prf->get_bytes(prf, protoid_chunk, NULL); - prf->get_bytes(prf, spi_chunk, NULL); - prf->get_bytes(prf, st->st_ni, NULL); - prf->get_bytes(prf, st->st_nr, keymat_i); - - i += prf_block_size; - if (i >= needed_space) - { - break; - } - - /* more keying material needed: prepare to go around again */ - prf->get_bytes(prf, keymat, NULL); - } - prf->destroy(prf); -} - -/* - * Produce the new key material of Quick Mode. - * RFC 2409 "IKE" section 5.5 - * specifies how this is to be done. - */ -static void compute_proto_keymat(struct state *st, u_int8_t protoid, - struct ipsec_proto_info *pi, enum endpoint ep) -{ - size_t needed_len = 0; /* bytes of keying material needed */ - - /* Add up the requirements for keying material - * (It probably doesn't matter if we produce too much!) - */ - switch (protoid) - { - case PROTO_IPSEC_ESP: - { - needed_len = kernel_alg_esp_enc_keylen(pi->attrs.transid); - - if (needed_len && pi->attrs.key_len) - { - needed_len = pi->attrs.key_len / BITS_PER_BYTE; - } - - switch (pi->attrs.transid) - { - case ESP_NULL: - needed_len = 0; - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - needed_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - needed_len += 4; - break; - default: - if (needed_len == 0) - { - bad_case(pi->attrs.transid); - } - } - - if (kernel_alg_esp_auth_ok(pi->attrs.auth, NULL)) - { - needed_len += kernel_alg_esp_auth_keylen(pi->attrs.auth); - } - else - { - switch (pi->attrs.auth) - { - case AUTH_ALGORITHM_NONE: - break; - case AUTH_ALGORITHM_HMAC_MD5: - needed_len += HMAC_MD5_KEY_LEN; - break; - case AUTH_ALGORITHM_HMAC_SHA1: - needed_len += HMAC_SHA1_KEY_LEN; - break; - case AUTH_ALGORITHM_DES_MAC: - default: - bad_case(pi->attrs.auth); - } - } - break; - } - case PROTO_IPSEC_AH: - { - switch (pi->attrs.transid) - { - case AH_MD5: - needed_len = HMAC_MD5_KEY_LEN; - break; - case AH_SHA: - needed_len = HMAC_SHA1_KEY_LEN; - break; - default: - bad_case(pi->attrs.transid); - } - break; - } - default: - bad_case(protoid); - } - - pi->keymat_len = needed_len; - - if (ep & EP_LOCAL) - { - compute_keymat_internal(st, protoid, pi->our_spi, needed_len, - &pi->our_keymat); - DBG(DBG_CRYPT, - DBG_dump("KEYMAT computed:\n", pi->our_keymat, - pi->keymat_len)); - } - if (ep & EP_REMOTE) - { - compute_keymat_internal(st, protoid, pi->attrs.spi, needed_len, - &pi->peer_keymat); - DBG(DBG_CRYPT, - DBG_dump("Peer KEYMAT computed:\n", pi->peer_keymat, - pi->keymat_len)); - } -} - -static void compute_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - compute_proto_keymat(st, PROTO_IPSEC_AH, &st->st_ah, ep); - } - if (st->st_esp.present) - { - compute_proto_keymat(st, PROTO_IPSEC_ESP, &st->st_esp, ep); - } -} - -static void wipe_proto_keymat(struct ipsec_proto_info *pi, enum endpoint ep) -{ - if (ep & EP_LOCAL) - { - memwipe(pi->our_keymat, pi->keymat_len); - } - if (ep & EP_REMOTE) - { - memwipe(pi->peer_keymat, pi->keymat_len); - } -} - -static void wipe_keymats(struct state *st, enum endpoint ep) -{ - if (st->st_ah.present) - { - wipe_proto_keymat(&st->st_ah, ep); - } - if (st->st_esp.present) - { - wipe_proto_keymat(&st->st_esp, ep); - } -} - -static bool uses_pubkey_auth(int auth) -{ - switch (auth) - { - case OAKLEY_RSA_SIG: - case OAKLEY_ECDSA_SIG: - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - case XAUTHInitRSA: - case XAUTHRespRSA: - return TRUE; - default: - return FALSE; - } -} - -/* build an ID payload - * Note: no memory is allocated for the body of the payload (tl->ptr). - * We assume it will end up being a pointer into a sufficiently - * stable datastructure. It only needs to last a short time. - */ -static void build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end) -{ - identification_t *id = resolve_myid(end->id); - - zero(hd); - hd->isaiid_idtype = id->get_type(id); - - switch (id->get_type(id)) - { - case ID_ANY: - hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr; - tl->len = addrbytesptr(&end->host_addr, - (const unsigned char **)&tl->ptr); /* sets tl->ptr too */ - break; - case ID_IPV4_ADDR: - case ID_IPV6_ADDR: - case ID_FQDN: - case ID_USER_FQDN: - case ID_DER_ASN1_DN: - case ID_KEY_ID: - *tl = id->get_encoding(id); - break; - default: - bad_case(id->get_type(id)); - } -} - -/* State Transition Functions. - * - * The definition of state_microcode_table in demux.c is a good - * overview of these routines. - * - * - Called from process_packet; result handled by complete_state_transition - * - struct state_microcode member "processor" points to these - * - these routine definitionss are in state order - * - these routines must be restartable from any point of error return: - * beware of memory allocated before any error. - * - output HDR is usually emitted by process_packet (if state_microcode - * member first_out_payload isn't ISAKMP_NEXT_NONE). - * - * The transition functions' functions include: - * - process and judge payloads - * - update st_iv (result of decryption is in st_new_iv) - * - build reply packet - */ - -/* Handle a Main Mode Oakley first packet (responder side). - * HDR;SA --> HDR;SA - */ -stf_status main_inI1_outR1(struct msg_digest *md) -{ - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - struct state *st; - connection_t *c; - struct isakmp_proposal proposal; - pb_stream proposal_pbs; - pb_stream r_sa_pbs; - u_int32_t ipsecdoisit; - lset_t policy = LEMPTY; - int vids_to_send = 0; - - /* We preparse the peer's proposal in order to determine - * the requested authentication policy (RSA or PSK) - */ - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sa_pd->payload.sa - , &sa_pd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - - backup_pbs(&proposal_pbs); - RETURN_STF_FAILURE(parse_isakmp_policy(&proposal_pbs - , proposal.isap_notrans, &policy)); - restore_pbs(&proposal_pbs); - - /* We are only considering candidate connections that match - * the requested authentication policy (RSA or PSK) - */ - c = find_host_connection(&md->iface->addr, pluto_port - , &md->sender, md->sender_port, policy); - - if (c == NULL && md->iface->ike_float) - { - c = find_host_connection(&md->iface->addr, NAT_T_IKE_FLOAT_PORT - , &md->sender, md->sender_port, policy); - } - - if (c == NULL) - { - /* See if a wildcarded connection can be found. - * We cannot pick the right connection, so we're making a guess. - * All Road Warrior connections are fair game: - * we pick the first we come across (if any). - * If we don't find any, we pick the first opportunistic - * with the smallest subnet that includes the peer. - * There is, of course, no necessary relationship between - * an Initiator's address and that of its client, - * but Food Groups kind of assumes one. - */ - { - connection_t *d; - - d = find_host_connection(&md->iface->addr - , pluto_port, (ip_address*)NULL, md->sender_port, policy); - - for (; d != NULL; d = d->hp_next) - { - if (d->kind == CK_GROUP) - { - /* ignore */ - } - else - { - if (d->kind == CK_TEMPLATE && !(d->policy & POLICY_OPPO)) - { - /* must be Road Warrior: we have a winner */ - c = d; - break; - } - - /* Opportunistic or Shunt: pick tightest match */ - if (addrinsubnet(&md->sender, &d->spd.that.client) - && (c == NULL || !subnetinsubnet(&c->spd.that.client, &d->spd.that.client))) - c = d; - } - } - } - - if (c == NULL) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but no connection has been authorized%s%s" - , ip_str(&md->iface->addr), ntohs(portof(&md->iface->addr)) - , (policy != LEMPTY) ? " with policy=" : "" - , (policy != LEMPTY) ? bitnamesof(sa_policy_bit_names, policy) : ""); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else if (c->kind != CK_TEMPLATE) - { - loglog(RC_LOG_SERIOUS, "initial Main Mode message received on %s:%u" - " but \"%s\" forbids connection" - , ip_str(&md->iface->addr), pluto_port, c->name); - /* XXX notification is in order! */ - return STF_IGNORE; - } - else - { - /* Create a temporary connection that is a copy of this one. - * His ID isn't declared yet. - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, NULL); - } - } - else if (c->kind == CK_TEMPLATE) - { - /* Create an instance - * This is a rare case: wildcard peer ID but static peer IP address - */ - c = rw_instantiate(c, &md->sender, md->sender_port, NULL, c->spd.that.id); - } - - /* Set up state */ - md->st = st = new_state(); - st->st_connection = c; - set_cur_state(st); /* (caller will reset cur_state) */ - st->st_try = 0; /* not our job to try again from start */ - st->st_policy = c->policy & ~POLICY_IPSEC_MASK; /* only as accurate as connection */ - - memcpy(st->st_icookie, md->hdr.isa_icookie, COOKIE_SIZE); - get_cookie(FALSE, st->st_rcookie, COOKIE_SIZE, &md->sender); - - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - st->st_doi = ISAKMP_DOI_IPSEC; - st->st_situation = SIT_IDENTITY_ONLY; /* We only support this */ - - if ((c->kind == CK_INSTANCE) && (c->spd.that.host_port != pluto_port)) - { - plog("responding to Main Mode from unknown peer %s:%u" - , ip_str(&c->spd.that.host_addr), c->spd.that.host_port); - } - else if (c->kind == CK_INSTANCE) - { - plog("responding to Main Mode from unknown peer %s" - , ip_str(&c->spd.that.host_addr)); - } - else - { - plog("responding to Main Mode"); - } - - /* parse_isakmp_sa also spits out a winning SA into our reply, - * so we have to build our md->reply and emit HDR before calling it. - */ - - /* determine how many Vendor ID payloads we will be sending */ - if (SEND_PLUTO_VID) - { - vids_to_send++; - } - if (SEND_CISCO_UNITY_VID) - { - vids_to_send++; - } - if (md->openpgp) - { - vids_to_send++; - } - if (SEND_XAUTH_VID) - { - vids_to_send++; - } - /* always send DPD Vendor ID */ - vids_to_send++; - if (md->nat_traversal_vid && nat_traversal_enabled) - { - vids_to_send++; - } - - /* HDR out. - * We can't leave this to comm_handle() because we must - * fill in the cookie. - */ - { - struct isakmp_hdr r_hdr = md->hdr; - - r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT; /* we won't ever turn on this bit */ - memcpy(r_hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - r_hdr.isa_np = ISAKMP_NEXT_SA; - if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) - return STF_INTERNAL_ERROR; - } - - /* start of SA out */ - { - struct isakmp_sa r_sa = sa_pd->payload.sa; - - r_sa.isasa_np = vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE; - - if (!out_struct(&r_sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - return STF_INTERNAL_ERROR; - } - - /* SA body in and out */ - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit, &proposal_pbs - ,&proposal, &r_sa_pbs, st, FALSE)); - - /* if enabled send Pluto Vendor ID */ - if (SEND_PLUTO_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_STRONGSWAN)) - { - return STF_INTERNAL_ERROR; - } - } - - /* if enabled send Cisco Unity Vendor ID */ - if (SEND_CISCO_UNITY_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_CISCO_UNITY)) - { - return STF_INTERNAL_ERROR; - } - } - - /* - * if the peer sent an OpenPGP Vendor ID we offer the same capability - */ - if (md->openpgp) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_OPENPGP)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do eXtended AUTHentication to the peer */ - if (SEND_XAUTH_VID) - { - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_XAUTH)) - { - return STF_INTERNAL_ERROR; - } - } - - /* Announce our ability to do Dead Peer Detection to the peer */ - if (!out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, VID_MISC_DPD)) - { - return STF_INTERNAL_ERROR; - } - - if (md->nat_traversal_vid && nat_traversal_enabled) - { - /* reply if NAT-Traversal draft is supported */ - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - - if (st->nat_traversal - && !out_vendorid(vids_to_send-- ? ISAKMP_NEXT_VID : ISAKMP_NEXT_NONE - , &md->rbody, md->nat_traversal_vid)) - { - return STF_INTERNAL_ERROR; - } - } - - close_message(&md->rbody); - - /* save initiator SA for HASH */ - free(st->st_p1isa.ptr); - st->st_p1isa = chunk_create(sa_pd->pbs.start, pbs_room(&sa_pd->pbs)); - st->st_p1isa = chunk_clone(st->st_p1isa); - - return STF_OK; -} - -/* STATE_MAIN_I1: HDR, SA --> auth dependent - * PSK_AUTH, DS_AUTH: --> HDR, KE, Ni - * - * The following are not yet implemented: - * PKE_AUTH: --> HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * RPKE_AUTH: --> HDR, [ HASH(1), ] Pubkey_r, Ke_i, - * Ke_i [,<Ke_i] - * - * We must verify that the proposal received matches one we sent. - */ -stf_status main_inR1_outI2(struct msg_digest *md) -{ - struct state *const st = md->st; - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* verify echoed SA */ - { - u_int32_t ipsecdoisit; - pb_stream proposal_pbs; - struct isakmp_proposal proposal; - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(preparse_isakmp_sa_body(&sapd->payload.sa - ,&sapd->pbs, &ipsecdoisit, &proposal_pbs, &proposal)); - if (proposal.isap_notrans != 1) - { - loglog(RC_LOG_SERIOUS, "a single Transform is required in a selecting Oakley Proposal; found %u" - , (unsigned)proposal.isap_notrans); - RETURN_STF_FAILURE(ISAKMP_BAD_PROPOSAL_SYNTAX); - } - RETURN_STF_FAILURE(parse_isakmp_sa_body(ipsecdoisit - , &proposal_pbs, &proposal, NULL, st, TRUE)); - } - - if (nat_traversal_enabled && md->nat_traversal_vid) - { - st->nat_traversal = nat_traversal_vid_to_method(md->nat_traversal_vid); - plog("enabling possible NAT-traversal with method %s" - , bitnamesof(natt_type_bitnames, st->nat_traversal)); - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - - /**************** build output packet HDR;KE;Ni ****************/ - - /* HDR out. - * We can't leave this to comm_handle() because the isa_np - * depends on the type of Auth (eventually). - */ - echo_hdr(md, FALSE, ISAKMP_NEXT_KE); - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gi, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody - , (cur_debugging & IMPAIR_BUST_MI2)? ISAKMP_NEXT_VID : np, "Ni")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MI2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic(np, &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Ni out */ - if (!build_and_ship_nonce(&st->st_ni, &md->rbody, np, "Ni")) - { - return STF_INTERNAL_ERROR; - } -#endif - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* Reinsert the state, using the responder cookie we just received */ - unhash_state(st); - memcpy(st->st_rcookie, md->hdr.isa_rcookie, COOKIE_SIZE); - insert_state(st); /* needs cookies, connection, and msgid (0) */ - - return STF_OK; -} - -/* STATE_MAIN_R1: - * PSK_AUTH, DS_AUTH: HDR, KE, Ni --> HDR, KE, Nr - * - * The following are not yet implemented: - * PKE_AUTH: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r - * --> HDR, KE, PubKey_i, PubKey_i - * RPKE_AUTH: - * HDR, [ HASH(1), ] Pubkey_r, Ke_i, Ke_i [,<Ke_i] - * --> HDR, PubKey_i, Ke_r, Ke_r - */ -stf_status main_inI2_outR2(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - - /* send CR if auth is RSA or ECDSA and no preloaded public key exists*/ - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - bool send_cr = !no_cr_send && pubkey_auth && !has_preloaded_public_key(st); - - u_int8_t np = ISAKMP_NEXT_NONE; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gi, "Gi", st->st_oakley.group, keyex_pbs)); - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - - np = (st->nat_traversal & NAT_T_WITH_RFC_VALUES) ? - ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS; - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /* decode certificate requests */ - st->st_connection->got_certrequest = FALSE; - decode_cr(md, st->st_connection); - - /**************** build output packet HDR;KE;Nr ****************/ - - /* HDR out done */ - - /* KE out */ - if (!build_and_ship_KE(st, &st->st_gr, st->st_oakley.group - , &md->rbody, ISAKMP_NEXT_NONCE)) - { - return STF_INTERNAL_ERROR; - } - -#ifdef DEBUG - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (cur_debugging & IMPAIR_BUST_MR2)? ISAKMP_NEXT_VID - : (send_cr? ISAKMP_NEXT_CR : np), "Nr")) - { - return STF_INTERNAL_ERROR; - } - if (cur_debugging & IMPAIR_BUST_MR2) - { - /* generate a pointless large VID payload to push message over MTU */ - pb_stream vid_pbs; - - if (!out_generic((send_cr)? ISAKMP_NEXT_CR : np, - &isakmp_vendor_id_desc, &md->rbody, &vid_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_zero(1500 /*MTU?*/, &vid_pbs, "Filler VID")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&vid_pbs); - } -#else - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody, - (send_cr)? ISAKMP_NEXT_CR : np, "Nr")) - return STF_INTERNAL_ERROR; -#endif - - /* CR out */ - if (send_cr) - { - if (st->st_connection->kind == CK_PERMANENT) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, np)) - { - return STF_INTERNAL_ERROR; - } - } - else - { - linked_list_t *list = collect_rw_ca_candidates(md); - int count = list->get_count(list); - bool error = FALSE; - - if (count) - { - enumerator_t *enumerator; - identification_t *ca; - - enumerator = list->create_enumerator(list); - while (enumerator->enumerate(enumerator, &ca)) - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, - ca->get_encoding(ca), &md->rbody, - --count ? ISAKMP_NEXT_CR : np)) - { - error = TRUE; - break; - } - } - enumerator->destroy(enumerator); - } - else - { - if (!build_and_ship_CR(CERT_X509_SIGNATURE, chunk_empty, - &md->rbody, np)) - { - error = TRUE; - } - } - list->destroy_offset(list, offsetof(identification_t, destroy)); - if (error) - { - return STF_INTERNAL_ERROR; - } - } - } - - if (st->nat_traversal & NAT_T_WITH_NATD) - { - if (!nat_traversal_add_natd(ISAKMP_NEXT_NONE, &md->rbody, md)) - { - return STF_INTERNAL_ERROR; - } - } - - /* finish message */ - close_message(&md->rbody); - - /* next message will be encrypted, but not this one. - * We could defer this calculation. - */ - compute_dh_shared(st, st->st_gi); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - update_iv(st); - - return STF_OK; -} - -/* STATE_MAIN_I2: - * SMF_PSK_AUTH: HDR, KE, Nr --> HDR*, IDi1, HASH_I - * SMF_DS_AUTH: HDR, KE, Nr --> HDR*, IDi1, [ CERT, ] SIG_I - * - * The following are not yet implemented. - * SMF_PKE_AUTH: HDR, KE, PubKey_i, PubKey_i - * --> HDR*, HASH_I - * SMF_RPKE_AUTH: HDR, PubKey_i, Ke_r, Ke_r - * --> HDR*, HASH_I - */ -stf_status main_inR2_outI3(struct msg_digest *md) -{ - struct state *const st = md->st; - pb_stream *const keyex_pbs = &md->chain[ISAKMP_NEXT_KE]->pbs; - pb_stream id_pbs; /* ID Payload; also used for hash calculation */ - - connection_t *c = st->st_connection; - certpolicy_t cert_policy = c->spd.this.sendcert; - cert_t *mycert = c->spd.this.cert; - bool requested, send_cert, send_cr; - bool pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - - int auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* KE in */ - RETURN_STF_FAILURE(accept_KE(&st->st_gr, "Gr", st->st_oakley.group, keyex_pbs)); - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* decode certificate requests */ - c->got_certrequest = FALSE; - decode_cr(md, c); - - /* free collected certificate requests since as initiator - * we don't heed them anyway - */ - if (c->requested_ca) - { - c->requested_ca->destroy_offset(c->requested_ca, - offsetof(identification_t, destroy)); - c->requested_ca = NULL; - } - - /* send certificate if auth is RSA, we have one and we want - * or are requested to send it - */ - requested = cert_policy == CERT_SEND_IF_ASKED && c->got_certrequest; - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /* send certificate request if we don't have a preloaded RSA public key */ - send_cr = !no_cr_send && send_cert && !has_preloaded_public_key(st); - - /* done parsing; initialize crypto */ - compute_dh_shared(st, st->st_gr); - if (!generate_skeyids_iv(st)) - { - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - if (st->nat_traversal & NAT_T_WITH_NATD) - { - nat_traversal_natd_lookup(md); - } - if (st->nat_traversal) - { - nat_traversal_show_result(st->nat_traversal, md->sender_port); - } - if (st->nat_traversal & NAT_T_WITH_KA) - { - nat_traversal_new_ka_event(); - } - - /*************** build output packet HDR*;IDii;HASH/SIG_I ***************/ - /* ??? NOTE: this is almost the same as main_inI3_outR3's code */ - - /* HDR* out done */ - - /* IDii out */ - { - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &c->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &id_pbs) - || !out_chunk(id_b, &id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - - struct isakmp_cert cert_hd; - cert_hd.isacert_np = (send_cr)? ISAKMP_NEXT_CR : ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* CR out */ - if (send_cr) - { - identification_t *ca = st->st_connection->spd.that.ca; - chunk_t cr = (ca) ? ca->get_encoding(ca) : chunk_empty; - - if (!build_and_ship_CR(CERT_X509_SIGNATURE, cr, &md->rbody, ISAKMP_NEXT_SIG)) - { - return STF_INTERNAL_ERROR; - } - } - - /* HASH_I or SIG_I out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, TRUE, &id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_I out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_I")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_I out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, c, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_I")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, except for fixed part of header */ - - /* st_new_iv was computed by generate_skeyids_iv */ - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - return STF_OK; -} - -/* Shared logic for asynchronous lookup of DNS KEY records. - * Used for STATE_MAIN_R2 and STATE_MAIN_I3. - */ - -enum key_oppo_step { - kos_null, - kos_his_txt -#ifdef USE_KEYRR - , kos_his_key -#endif -}; - -struct key_continuation { - struct adns_continuation ac; /* common prefix */ - struct msg_digest *md; - enum key_oppo_step step; - bool failure_ok; - err_t last_ugh; -}; - -typedef stf_status (key_tail_fn)(struct msg_digest *md - , struct key_continuation *kc); - -static void report_key_dns_failure(identification_t *id, err_t ugh) -{ - loglog(RC_LOG_SERIOUS, "no RSA public key known for '%Y'" - "; DNS search for KEY failed (%s)", id, ugh); -} - - -/* Processs the Main Mode ID Payload and the Authenticator - * (Hash or Signature Payload). - * If a DNS query is still needed to get the other host's public key, - * the query is initiated and STF_SUSPEND is returned. - * Note: parameter kc is a continuation containing the results from - * the previous DNS query, or NULL indicating no query has been issued. - */ -static stf_status -main_id_and_auth(struct msg_digest *md - , bool initiator /* are we the Initiator? */ - , cont_fn_t cont_fn /* continuation function */ - , const struct key_continuation *kc /* current state, can be NULL */ -) -{ - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - struct state *st = md->st; - identification_t *peer; - stf_status r = STF_OK; - - /* ID Payload in */ - if (!decode_peer_id(md, &peer)) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hash the ID Payload. - * main_mode_hash requires idpl->cur to be at end of payload - * so we temporarily set if so. - */ - { - pb_stream *idpl = &md->chain[ISAKMP_NEXT_ID]->pbs; - u_int8_t *old_cur = idpl->cur; - - idpl->cur = idpl->roof; - main_mode_hash(st, &hash, !initiator, idpl); - idpl->cur = old_cur; - } - - switch (st->st_oakley.auth) - { - case OAKLEY_PRESHARED_KEY: - case XAUTHInitPreShared: - case XAUTHRespPreShared: - { - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; - - if (pbs_left(hash_pbs) != hash.len - || memcmp(hash_pbs->cur, hash.ptr, hash.len) != 0) - { - DBG_cond_dump(DBG_CRYPT, "received HASH:" - , hash_pbs->cur, pbs_left(hash_pbs)); - loglog(RC_LOG_SERIOUS, "received Hash Payload does not match computed value"); - /* XXX Could send notification back */ - r = STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; - } - } - break; - - case OAKLEY_RSA_SIG: - case XAUTHInitRSA: - case XAUTHRespRSA: - r = check_signature(KEY_RSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - kc == NULL ? NULL : kc->ac.keys_from_dns, -#endif /* USE_KEYRR */ - kc == NULL ? NULL : kc->ac.gateways_from_dns - ); - - if (r == STF_SUSPEND) - { - err_t ugh = NULL; -#ifdef ADNS - /* initiate/resume asynchronous DNS lookup for key */ - struct key_continuation *nkc = malloc_thing(struct key_continuation); - enum key_oppo_step step_done = kc == NULL? kos_null : kc->step; - - /* Record that state is used by a suspended md */ - passert(st->st_suspended_md == NULL); - st->st_suspended_md = md; - - nkc->failure_ok = FALSE; - nkc->md = md; - - switch (step_done) - { - case kos_null: - /* first try: look for the TXT records */ - nkc->step = kos_his_txt; -#ifdef USE_KEYRR - nkc->failure_ok = TRUE; -#endif - ugh = start_adns_query(peer, peer, T_TXT, cont_fn, &nkc->ac); - break; - -#ifdef USE_KEYRR - case kos_his_txt: - /* second try: look for the KEY records */ - nkc->step = kos_his_key; - ugh = start_adns_query(peer, NULL, T_KEY, cont_fn, &nkc->ac); - break; -#endif /* USE_KEYRR */ - - default: - bad_case(step_done); - } -#else /* ADNS */ - ugh = "adns not supported"; -#endif /* ADNS */ - if (ugh != NULL) - { - report_key_dns_failure(peer, ugh); - st->st_suspended_md = NULL; - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - } - break; - - case OAKLEY_ECDSA_256: - case OAKLEY_ECDSA_384: - case OAKLEY_ECDSA_521: - r = check_signature(KEY_ECDSA, peer, st, hash, - &md->chain[ISAKMP_NEXT_SIG]->pbs, -#ifdef USE_KEYRR - NULL, -#endif /* USE_KEYRR */ - NULL); - break; - - default: - bad_case(st->st_oakley.auth); - } - if (r != STF_OK) - { - peer->destroy(peer); - return r; - } - DBG(DBG_CRYPT, DBG_log("authentication succeeded")); - - /* - * With the peer ID known, let's see if we need to switch connections. - */ - if (!switch_connection(md, peer, initiator)) - { - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - peer->destroy(peer); - return r; -} - -/* This continuation is called as part of either - * the main_inI3_outR3 state or main_inR3 state. - * - * The "tail" function is the corresponding tail - * function main_inI3_outR3_tail | main_inR3_tail, - * either directly when the state is started, or via - * adns continuation. - * - * Basically, we go around in a circle: - * main_in?3* -> key_continue - * ^ \ - * / V - * adns main_in?3*_tail - * ^ | - * \ V - * main_id_and_auth - * - * until such time as main_id_and_auth is able - * to find authentication, or we run out of things - * to try. - */ -static void key_continue(struct adns_continuation *cr, err_t ugh, - key_tail_fn *tail) -{ - struct key_continuation *kc = (void *)cr; - struct state *st = kc->md->st; - - passert(cur_state == NULL); - - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - stf_status r; - - passert(st->st_suspended_md == kc->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - - if (!kc->failure_ok && ugh != NULL) - { - report_key_dns_failure(st->st_connection->spd.that.id, ugh); - r = STF_FAIL + ISAKMP_INVALID_KEY_INFORMATION; - } - else - { - -#ifdef USE_KEYRR - passert(kc->step == kos_his_txt || kc->step == kos_his_key); -#else - passert(kc->step == kos_his_txt); -#endif - kc->last_ugh = ugh; /* record previous error in case we need it */ - r = (*tail)(kc->md, kc); - } - complete_state_transition(&kc->md, r); - } - if (kc->md != NULL) - { - release_md(kc->md); - } - cur_state = NULL; -} - -/* STATE_MAIN_R2: - * PSK_AUTH: HDR*, IDi1, HASH_I --> HDR*, IDr1, HASH_R - * DS_AUTH: HDR*, IDi1, [ CERT, ] SIG_I --> HDR*, IDr1, [ CERT, ] SIG_R - * PKE_AUTH, RPKE_AUTH: HDR*, HASH_I --> HDR*, HASH_R - * - * Broken into parts to allow asynchronous DNS lookup. - * - * - main_inI3_outR3 to start - * - main_inI3_outR3_tail to finish or suspend for DNS lookup - * - main_inI3_outR3_continue to start main_inI3_outR3_tail again - */ -static key_tail_fn main_inI3_outR3_tail; /* forward */ - -stf_status main_inI3_outR3(struct msg_digest *md) -{ - return main_inI3_outR3_tail(md, NULL); -} - -static void main_inI3_outR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inI3_outR3_tail); -} - -static stf_status -main_inI3_outR3_tail(struct msg_digest *md -, struct key_continuation *kc) -{ - struct state *const st = md->st; - u_int8_t auth_payload; - pb_stream r_id_pbs; /* ID Payload; also used for hash calculation */ - certpolicy_t cert_policy; - cert_t *mycert; - bool pubkey_auth, send_cert, requested; - - /* ID and HASH_I or SIG_I in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, FALSE - , main_inI3_outR3_continue - , kc); - - if (r != STF_OK) - { - return r; - } - } - - /* send certificate if pubkey authentication is used, we have one - * and we want or are requested to send it - */ - cert_policy = st->st_connection->spd.this.sendcert; - mycert = st->st_connection->spd.this.cert; - requested = cert_policy == CERT_SEND_IF_ASKED - && st->st_connection->got_certrequest; - pubkey_auth = uses_pubkey_auth(st->st_oakley.auth); - send_cert = pubkey_auth && mycert && - mycert->cert->get_type(mycert->cert) == CERT_X509 && - (cert_policy == CERT_ALWAYS_SEND || requested); - - /*************** build output packet HDR*;IDir;HASH/SIG_R ***************/ - /* proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - */ - /* ??? NOTE: this is almost the same as main_inR2_outI3's code */ - - /* HDR* out - * If auth were PKE_AUTH or RPKE_AUTH, ISAKMP_NEXT_HASH would - * be first payload. - */ - echo_hdr(md, TRUE, ISAKMP_NEXT_ID); - - auth_payload = pubkey_auth ? ISAKMP_NEXT_SIG : ISAKMP_NEXT_HASH; - - /* IDir out */ - { - /* id_hd should be struct isakmp_id, but struct isakmp_ipsec_id - * allows build_id_payload() to work for both phases. - */ - struct isakmp_ipsec_id id_hd; - chunk_t id_b; - - build_id_payload(&id_hd, &id_b, &st->st_connection->spd.this); - id_hd.isaiid_np = (send_cert)? ISAKMP_NEXT_CERT : auth_payload; - if (!out_struct(&id_hd, &isakmp_ipsec_identification_desc, &md->rbody, &r_id_pbs) - || !out_chunk(id_b, &r_id_pbs, "my identity")) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&r_id_pbs); - } - - /* CERT out */ - if (pubkey_auth) - { - DBG(DBG_CONTROL, - DBG_log("our certificate policy is %N", cert_policy_names, cert_policy) - ) - if (mycert && mycert->cert->get_type(mycert->cert) == CERT_X509) - { - const char *request_text = ""; - - if (cert_policy == CERT_SEND_IF_ASKED) - { - request_text = (send_cert)? "upon request":"without request"; - } - plog("we have a cert %s sending it %s" - , send_cert? "and are":"but are not", request_text); - } - else - { - plog("we don't have a cert"); - } - } - if (send_cert) - { - bool success = FALSE; - chunk_t cert_encoding; - pb_stream cert_pbs; - struct isakmp_cert cert_hd; - - cert_hd.isacert_np = ISAKMP_NEXT_SIG; - cert_hd.isacert_type = CERT_X509_SIGNATURE; - - if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, &md->rbody, &cert_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (mycert->cert->get_encoding(mycert->cert, CERT_ASN1_DER, - &cert_encoding)) - { - success = out_chunk(cert_encoding, &cert_pbs, "CERT"); - free(cert_encoding.ptr); - } - if (!success) - { - return STF_INTERNAL_ERROR; - } - close_output_pbs(&cert_pbs); - } - - /* HASH_R or SIG_R out */ - { - chunk_t hash = chunk_alloca(MAX_DIGEST_LEN); - - main_mode_hash(st, &hash, FALSE, &r_id_pbs); - - if (auth_payload == ISAKMP_NEXT_HASH) - { - /* HASH_R out */ - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_hash_desc, &md->rbody, - hash.ptr, hash.len, "HASH_R")) - { - return STF_INTERNAL_ERROR; - } - } - else - { - /* SIG_R out */ - u_char sig_val[RSA_MAX_OCTETS]; - signature_scheme_t scheme; - size_t sig_len; - - scheme = oakley_to_signature_scheme(st->st_oakley.auth); - - sig_len = sign_hash(scheme, st->st_connection, sig_val, hash); - if (sig_len == 0) - { - loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature"); - return STF_FAIL + ISAKMP_AUTHENTICATION_FAILED; - } - - if (!out_generic_raw(ISAKMP_NEXT_NONE, &isakmp_signature_desc - , &md->rbody, sig_val, sig_len, "SIG_R")) - { - return STF_INTERNAL_ERROR; - } - } - } - - /* encrypt message, sans fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - /* Last block of Phase 1 (R3), kept for Phase 2 IV generation */ - DBG_cond_dump(DBG_CRYPT, "last encrypted block of Phase 1:" - , st->st_new_iv, st->st_new_iv_len); - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - return STF_OK; -} - -/* STATE_MAIN_I3: - * Handle HDR*;IDir;HASH/SIG_R from responder. - * - * Broken into parts to allow asynchronous DNS for KEY records. - * - * - main_inR3 to start - * - main_inR3_tail to finish or suspend for DNS lookup - * - main_inR3_continue to start main_inR3_tail again - */ - -static key_tail_fn main_inR3_tail; /* forward */ - -stf_status main_inR3(struct msg_digest *md) -{ - return main_inR3_tail(md, NULL); -} - -static void main_inR3_continue(struct adns_continuation *cr, err_t ugh) -{ - key_continue(cr, ugh, main_inR3_tail); -} - -static stf_status main_inR3_tail(struct msg_digest *md, - struct key_continuation *kc) -{ - struct state *const st = md->st; - - /* ID and HASH_R or SIG_R in - * Note: this may switch the connection being used! - */ - { - stf_status r = main_id_and_auth(md, TRUE, main_inR3_continue, kc); - - if (r != STF_OK) - { - return r; - } - } - - /**************** done input ****************/ - - ISAKMP_SA_established(st->st_connection, st->st_serialno); - - /* Save Phase 1 IV */ - st->st_ph1_iv_len = st->st_new_iv_len; - set_ph1_iv(st, st->st_new_iv); - - - update_iv(st); /* finalize our Phase 1 IV */ - - return STF_OK; -} - -/* Handle first message of Phase 2 -- Quick Mode. - * HDR*, HASH(1), SA, Ni [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] - * (see RFC 2409 "IKE" 5.5) - * Installs inbound IPsec SAs. - * Although this seems early, we know enough to do so, and - * this way we know that it is soon enough to catch all - * packets that other side could send using this IPsec SA. - * - * Broken into parts to allow asynchronous DNS for TXT records: - * - * - quick_inI1_outR1 starts the ball rolling. - * It checks and parses enough to learn the Phase 2 IDs - * - * - quick_inI1_outR1_tail does the rest of the job - * unless DNS must be consulted. In that case, - * it starts a DNS query, salts away what is needed - * to continue, and suspends. Calls - * + quick_inI1_outR1_start_query - * + quick_inI1_outR1_process_answer - * - * - quick_inI1_outR1_continue will restart quick_inI1_outR1_tail - * when DNS comes back with an answer. - * - * A big chunk of quick_inI1_outR1_tail is executed twice. - * This is necessary because the set of connections - * might change while we are awaiting DNS. - * When first called, gateways_from_dns == NULL. If DNS is - * consulted asynchronously, gateways_from_dns != NULL the second time. - * Remember that our state object might disappear too! - * - * - * If the connection is opportunistic, we must verify delegation. - * - * 1. Check that we are authorized to be SG for - * our client. We look for the TXT record that - * delegates us. We also check that the public - * key (if present) matches the private key we used. - * Eventually, we should probably require DNSsec - * authentication for our side. - * - * 2. If our client TXT record did not include a - * public key, check the KEY record indicated - * by the identity in the TXT record. - * - * 3. If the peer's client is the peer itself, we - * consider it authenticated. Otherwise, we check - * the TXT record for the client to see that - * the identity of the SG matches the peer and - * that some public key (if present in the TXT) - * matches. We need not check the public key if - * it isn't in the TXT record. - * - * Since p isn't yet instantiated, we need to look - * in c for description of peer. - * - * We cannot afford to block waiting for a DNS query. - * The code here is structured as two halves: - * - process the result of just completed - * DNS query (if any) - * - if another query is needed, initiate the next - * DNS query and suspend - */ - -enum verify_oppo_step { - vos_fail, - vos_start, - vos_our_client, - vos_our_txt, -#ifdef USE_KEYRR - vos_our_key, -#endif /* USE_KEYRR */ - vos_his_client, - vos_done -}; - -static const char *const verify_step_name[] = { - "vos_fail", - "vos_start", - "vos_our_client", - "vos_our_txt", -#ifdef USE_KEYRR - "vos_our_key", -#endif /* USE_KEYRR */ - "vos_his_client", - "vos_done" -}; - -/* hold anything we can handle of a Phase 2 ID */ -struct p2id { - ip_subnet net; - u_int8_t proto; - u_int16_t port; -}; - -struct verify_oppo_bundle { - enum verify_oppo_step step; - bool failure_ok; /* if true, quick_inI1_outR1_continue will try - * other things on DNS failure */ - struct msg_digest *md; - struct p2id my, his; - unsigned int new_iv_len; /* p1st's might change */ - u_char new_iv[MAX_DIGEST_LEN]; - /* int whackfd; */ /* not needed because we are Responder */ -}; - -struct verify_oppo_continuation { - struct adns_continuation ac; /* common prefix */ - struct verify_oppo_bundle b; -}; - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b - , struct adns_continuation *ac); - -stf_status quick_inI1_outR1(struct msg_digest *md) -{ - const struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - struct verify_oppo_bundle b; - - /* HASH(1) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , p1st, &md->hdr.isa_msgid, FALSE) - , "HASH(1)", "Quick I1"); - - /* [ IDci, IDcr ] in - * We do this now (probably out of physical order) because - * we wish to select the correct connection before we consult - * it for policy. - */ - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (initiator is peer) */ - - if (!decode_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &b.his.net, "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* Hack for MS 818043 NAT-T Update */ - - if (id_pd->payload.ipsec_id.isaiid_idtype == ID_FQDN) - { - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - } - - /* End Hack for MS 818043 NAT-T Update */ - - b.his.proto = id_pd->payload.ipsec_id.isaiid_protoid; - b.his.port = id_pd->payload.ipsec_id.isaiid_port; - b.his.net.addr.u.v4.sin_port = htons(b.his.port); - - /* IDcr (we are responder) */ - - if (!decode_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &b.my.net, "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - b.my.proto = id_pd->next->payload.ipsec_id.isaiid_protoid; - b.my.port = id_pd->next->payload.ipsec_id.isaiid_port; - b.my.net.addr.u.v4.sin_port = htons(b.my.port); - } - else - { - /* implicit IDci and IDcr: peer and self */ - if (!sameaddrtype(&c->spd.this.host_addr, &c->spd.that.host_addr)) - { - return STF_FAIL; - } - happy(addrtosubnet(&c->spd.this.host_addr, &b.my.net)); - happy(addrtosubnet(&c->spd.that.host_addr, &b.his.net)); - b.his.proto = b.my.proto = 0; - b.his.port = b.my.port = 0; - } - b.step = vos_start; - b.md = md; - b.new_iv_len = p1st->st_new_iv_len; - memcpy(b.new_iv, p1st->st_new_iv, p1st->st_new_iv_len); - return quick_inI1_outR1_tail(&b, NULL); -} - -#ifdef ADNS - -static void -report_verify_failure(struct verify_oppo_bundle *b, err_t ugh) -{ - struct state *st = b->md->st; - char fgwb[ADDRTOT_BUF] - , cb[ADDRTOT_BUF]; - ip_address client; - err_t which = NULL; - - switch (b->step) - { - case vos_our_client: - case vos_our_txt: -#ifdef USE_KEYRR - case vos_our_key: -#endif /* USE_KEYRR */ - which = "our"; - networkof(&b->my.net, &client); - break; - - case vos_his_client: - which = "his"; - networkof(&b->his.net, &client); - break; - - case vos_start: - case vos_done: - case vos_fail: - default: - bad_case(b->step); - } - - addrtot(&st->st_connection->spd.that.host_addr, 0, fgwb, sizeof(fgwb)); - addrtot(&client, 0, cb, sizeof(cb)); - loglog(RC_OPPOFAILURE - , "gateway %s wants connection with %s as %s client, but DNS fails to confirm delegation: %s" - , fgwb, cb, which, ugh); -} - -static void quick_inI1_outR1_continue(struct adns_continuation *cr, err_t ugh) -{ - stf_status r; - struct verify_oppo_continuation *vc = (void *)cr; - struct verify_oppo_bundle *b = &vc->b; - struct state *st = b->md->st; - - passert(cur_state == NULL); - /* if st == NULL, our state has been deleted -- just clean up */ - if (st != NULL) - { - passert(st->st_suspended_md == b->md); - st->st_suspended_md = NULL; /* no longer connected or suspended */ - cur_state = st; - if (!b->failure_ok && ugh != NULL) - { - report_verify_failure(b, ugh); - r = STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - r = quick_inI1_outR1_tail(b, cr); - } - complete_state_transition(&b->md, r); - } - if (b->md != NULL) - { - release_md(b->md); - } - cur_state = NULL; -} - -static stf_status quick_inI1_outR1_start_query(struct verify_oppo_bundle *b, - enum verify_oppo_step next_step) -{ - struct msg_digest *md = b->md; - struct state *p1st = md->st; - connection_t *c = p1st->st_connection; - struct verify_oppo_continuation *vc = malloc_thing(struct verify_oppo_continuation); - identification_t *id; /* subject of query */ - identification_t *our_id; /* needed for myid playing */ - identification_t *our_id_space; /* ephemeral: no need for unshare_id_content */ - ip_address client; - err_t ugh = NULL; - - /* Record that state is used by a suspended md */ - b->step = next_step; /* not just vc->b.step */ - vc->b = *b; - passert(p1st->st_suspended_md == NULL); - p1st->st_suspended_md = b->md; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding with DNS query - from %s to %s new state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* Resolve %myid in a cheesy way. - * We have to do the resolution because start_adns_query - * et al have insufficient information to do so. - * If %myid is already known, we'll use that value - * (XXX this may be a mistake: it could be stale). - * If %myid is unknown, we should check to see if - * there are credentials for the IP address or the FQDN. - * Instead, we'll just assume the IP address since we are - * acting as the responder and only the IP address would - * have gotten it to us. - * We don't even try to do this for the other side: - * %myid makes no sense for the other side (but it is syntactically - * legal). - */ - our_id = resolve_myid(c->spd.this.id); - if (our_id->get_type(our_id) == ID_ANY) - { - our_id_space = identification_create_from_sockaddr((sockaddr_t*)&c->spd.this.host_addr); - our_id = our_id_space; - } - - switch (next_step) - { - case vos_our_client: - networkof(&b->my.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , our_id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - case vos_our_txt: - vc->b.failure_ok = b->failure_ok = TRUE; - ugh = start_adns_query(our_id - , our_id /* self as SG */ - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - -#ifdef USE_KEYRR - case vos_our_key: - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(our_id - , NULL - , T_KEY - , quick_inI1_outR1_continue - , &vc->ac); - break; -#endif - - case vos_his_client: - networkof(&b->his.net, &client); - id = identification_create_from_sockaddr((sockaddr_t*)&client); - vc->b.failure_ok = b->failure_ok = FALSE; - ugh = start_adns_query(id - , c->spd.that.id - , T_TXT - , quick_inI1_outR1_continue - , &vc->ac); - break; - - default: - bad_case(next_step); - } - - if (ugh != NULL) - { - /* note: we'd like to use vc->b but vc has been freed - * so we have to use b. This is why we plunked next_state - * into b, not just vc->b. - */ - report_verify_failure(b, ugh); - p1st->st_suspended_md = NULL; - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else - { - return STF_SUSPEND; - } -} - -static enum verify_oppo_step quick_inI1_outR1_process_answer( - struct verify_oppo_bundle *b, - struct adns_continuation *ac, - struct state *p1st) -{ - connection_t *c = p1st->st_connection; - enum verify_oppo_step next_step = vos_our_client; - err_t ugh = NULL; - - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - DBG_log("responding on demand from %s to %s state: %s" - , ours, his, verify_step_name[b->step]); - }); - - /* process just completed DNS query (if any) */ - switch (b->step) - { - case vos_start: - /* no query to digest */ - next_step = vos_our_client; - break; - - case vos_our_client: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - struct gw_info *gwp; - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - ugh = "our client does not delegate us as its Security Gateway"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "our client delegates us as its Security Gateway but with the wrong public key"; - /* If there is no key in the TXT record, - * we count it as a win, but we will have - * to separately fetch and check the KEY record. - * If there is a key from the TXT record, - * we count it as a win if we match the key. - */ - if (!gwp->gw_key_present) - { - next_step = vos_our_txt; - ugh = NULL; /* good! */ - break; - } - else if (private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - case vos_our_txt: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - struct gw_info *gwp; - - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { -#ifdef USE_KEYRR - /* not an error yet, because we have to check KEY RR as well */ - ugh = NULL; -#else - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; -#endif - if (gwp->gw_key_present - && private->belongs_to(private, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } -#ifdef USE_KEYRR - next_step = vos_our_key; -#endif - } - } - } - break; - -#ifdef USE_KEYRR - case vos_our_key: - next_step = vos_his_client; - { - private_key_t *private = get_private_key(c); - - if (private == NULL) - { - ugh = "we don't know our own key"; - break; - } - { - pubkey_list_t *kp; - - ugh = "our client delegation depends on our missing " RRNAME " record"; - for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next) - { - ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key"; - if (private->belongs_to(private, kp->key->public_key)) - { - /* do this only once a day */ - if (!logged_txt_warning) - { - loglog(RC_LOG_SERIOUS, "found KEY RR but not TXT RR. See http://www.freeswan.org/err/txt-change.html."); - logged_txt_warning = TRUE; - } - ugh = NULL; /* good! */ - break; - } - } - } - } - break; -#endif /* USE_KEYRR */ - - case vos_his_client: - next_step = vos_done; - { - public_key_t *pub_key; - struct gw_info *gwp; - - /* check that the public key that authenticated - * the ISAKMP SA (p1st) will do for this gateway. - */ - pub_key = p1st->st_peer_pubkey->public_key; - - ugh = "peer's client does not delegate to peer"; - for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - ugh = "peer and its client disagree about public key"; - /* If there is a key from the TXT record, - * we count it as a win if we match the key. - * If there was no key, we claim a match since - * it implies fetching a KEY from the same - * place we must have gotten it. - */ - if (!gwp->gw_key_present || - pub_key->equals(pub_key, gwp->key->public_key)) - { - ugh = NULL; /* good! */ - break; - } - } - } - break; - - default: - bad_case(b->step); - } - - if (ugh != NULL) - { - report_verify_failure(b, ugh); - next_step = vos_fail; - } - return next_step; -} - -#endif /* ADNS */ - -static stf_status quick_inI1_outR1_tail(struct verify_oppo_bundle *b, - struct adns_continuation *ac) -{ - struct msg_digest *md = b->md; - struct state *const p1st = md->st; - connection_t *c = p1st->st_connection; - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - ip_subnet *our_net = &b->my.net - , *his_net = &b->his.net; - - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* from where to start hashing */ - - /* Now that we have identities of client subnets, we must look for - * a suitable connection (our current one only matches for hosts). - */ - { - connection_t *p = find_client_connection(c - , our_net, his_net, b->my.proto, b->my.port, b->his.proto, b->his.port); - - if (p == NULL) - { - /* This message occurs in very puzzling circumstances - * so we must add as much information and beauty as we can. - */ - struct end - me = c->spd.this, - he = c->spd.that; - char buf[2*SUBNETTOT_BUF + 2*ADDRTOT_BUF + 2*BUF_LEN + 2*ADDRTOT_BUF + 12]; /* + 12 for separating */ - size_t l; - - me.client = *our_net; - me.has_client = !subnetisaddr(our_net, &me.host_addr); - me.protocol = b->my.proto; - me.port = b->my.port; - - he.client = *his_net; - he.has_client = !subnetisaddr(his_net, &he.host_addr); - he.protocol = b->his.proto; - he.port = b->his.port; - - l = format_end(buf, sizeof(buf), &me, NULL, TRUE, LEMPTY); - l += snprintf(buf + l, sizeof(buf) - l, "..."); - (void)format_end(buf + l, sizeof(buf) - l, &he, NULL, FALSE, LEMPTY); - plog("cannot respond to IPsec SA request" - " because no connection is known for %s" - , buf); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - else if (p != c) - { - /* We've got a better connection: it can support the - * specified clients. But it may need instantiation. - */ - if (p->kind == CK_TEMPLATE) - { - /* Yup, it needs instantiation. How much? - * Is it a Road Warrior connection (simple) - * or is it an Opportunistic connection (needing gw validation)? - */ - if (p->policy & POLICY_OPPO) - { -#ifdef ADNS - /* Opportunistic case: delegation must be verified. - * Here be dragons. - */ - enum verify_oppo_step next_step; - ip_address our_client, his_client; - - passert(subnetishost(our_net) && subnetishost(his_net)); - networkof(our_net, &our_client); - networkof(his_net, &his_client); - - next_step = quick_inI1_outR1_process_answer(b, ac, p1st); - if (next_step == vos_fail) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* short circuit: if peer's client is self, - * accept that we've verified delegation in Phase 1 - */ - if (next_step == vos_his_client - && sameaddr(&c->spd.that.host_addr, &his_client)) - { - next_step = vos_done; - } - - /* the second chunk: initiate the next DNS query (if any) */ - DBG(DBG_CONTROL, - { - char ours[SUBNETTOT_BUF]; - char his[SUBNETTOT_BUF]; - - subnettot(&c->spd.this.client, 0, ours, sizeof(ours)); - subnettot(&c->spd.that.client, 0, his, sizeof(his)); - - DBG_log("responding on demand from %s to %s new state: %s" - , ours, his, verify_step_name[next_step]); - }); - - /* start next DNS query and suspend (if necessary) */ - if (next_step != vos_done) - { - return quick_inI1_outR1_start_query(b, next_step); - } - - /* Instantiate inbound Opportunistic connection, - * carrying over authenticated peer ID - * and filling in a few more details. - * We used to include gateways_from_dns, but that - * seems pointless at this stage of negotiation. - * We should record DNS sec use, if any -- belongs in - * state during perhaps. - */ - p = oppo_instantiate(p, &c->spd.that.host_addr, c->spd.that.id - , NULL, &our_client, &his_client); -#else /* ADNS */ - plog("opportunistic connections not supported because" - " adns is not available"); - return STF_INTERNAL_ERROR; -#endif /* ADNS */ - } - else - { - /* Plain Road Warrior: - * instantiate, carrying over authenticated peer ID - */ - host_t *vip = c->spd.that.host_srcip; - - p = rw_instantiate(p, &c->spd.that.host_addr, md->sender_port - , his_net, c->spd.that.id); - - /* inherit any virtual IP assigned by a Mode Config exchange */ - if (p->spd.that.modecfg && c->spd.that.modecfg && - subnetisaddr(his_net, (ip_address*)vip->get_sockaddr(vip))) - { - DBG(DBG_CONTROL, - DBG_log("inheriting virtual IP source address %H from ModeCfg", vip) - ) - p->spd.that.host_srcip->destroy(p->spd.that.host_srcip); - p->spd.that.host_srcip = vip->clone(vip); - p->spd.that.client = c->spd.that.client; - p->spd.that.has_client = TRUE; - } - - if (c->policy & (POLICY_XAUTH_RSASIG | POLICY_XAUTH_PSK) && - c->xauth_identity && !p->xauth_identity) - { - DBG(DBG_CONTROL, - DBG_log("inheriting XAUTH identity %Y", c->xauth_identity) - ) - p->xauth_identity = c->xauth_identity->clone(c->xauth_identity); - } - } - } -#ifdef DEBUG - /* temporarily bump up cur_debugging to get "using..." message - * printed if we'd want it with new connection. - */ - { - lset_t old_cur_debugging = cur_debugging; - - cur_debugging |= p->extra_debugging; - DBG(DBG_CONTROL, DBG_log("using connection \"%s\"", p->name)); - cur_debugging = old_cur_debugging; - } -#endif - c = p; - } - /* fill in the client's true ip address/subnet */ - if (p->spd.that.has_client_wildcard) - { - p->spd.that.client = *his_net; - p->spd.that.has_client_wildcard = FALSE; - } - else if (is_virtual_connection(c)) - { - c->spd.that.client = *his_net; - c->spd.that.virt = NULL; - if (subnetishost(his_net) && addrinsubnet(&c->spd.that.host_addr, his_net)) - { - c->spd.that.has_client = FALSE; - } - } - - /* fill in the client's true port */ - if (p->spd.that.has_port_wildcard) - { - int port = htons(b->his.port); - - setportof(port, &p->spd.that.host_addr); - setportof(port, &p->spd.that.client.addr); - - p->spd.that.port = b->his.port; - p->spd.that.has_port_wildcard = FALSE; - } - } - - /* now that we are sure of our connection, create our new state */ - { - enum endpoint ep = EP_LOCAL; - struct state *const st = duplicate_state(p1st); - - /* first: fill in missing bits of our new state object - * note: we don't copy over st_peer_pubkey, the public key - * that authenticated the ISAKMP SA. We only need it in this - * routine, so we can "reach back" to p1st to get it. - */ - - if (st->st_connection != c) - { - connection_t *t = st->st_connection; - - st->st_connection = c; - set_cur_connection(c); - connection_discard(t); - } - - st->st_try = 0; /* not our job to try again from start */ - - st->st_msgid = md->hdr.isa_msgid; - - st->st_new_iv_len = b->new_iv_len; - memcpy(st->st_new_iv, b->new_iv, b->new_iv_len); - - set_cur_state(st); /* (caller will reset) */ - md->st = st; /* feed back new state */ - - st->st_peeruserprotoid = b->his.proto; - st->st_peeruserport = b->his.port; - st->st_myuserprotoid = b->my.proto; - st->st_myuserport = b->my.port; - - insert_state(st); /* needs cookies, connection, and msgid */ - - /* copy the connection's - * IPSEC policy into our state. The ISAKMP policy is water under - * the bridge, I think. It will reflect the ISAKMP SA that we - * are using. - */ - st->st_policy = (p1st->st_policy & POLICY_ISAKMP_MASK) - | (c->policy & ~POLICY_ISAKMP_MASK); - - if (p1st->nat_traversal & NAT_T_DETECTED) - { - st->nat_traversal = p1st->nat_traversal; - nat_traversal_change_port_lookup(md, md->st); - } - else - { - st->nat_traversal = 0; - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* Start the output packet. - * - * proccess_packet() would automatically generate the HDR* - * payload if smc->first_out_payload is not ISAKMP_NEXT_NONE. - * We don't do this because we wish there to be no partially - * built output packet if we need to suspend for asynch DNS. - * - * We build the reply packet as we parse the message since - * the parse_ipsec_sa_body emits the reply SA - */ - - /* HDR* out */ - echo_hdr(md, TRUE, ISAKMP_NEXT_HASH); - - /* HASH(2) out -- first pass */ - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_SA); - - /* process SA (in and out) */ - { - struct payload_digest *const sapd = md->chain[ISAKMP_NEXT_SA]; - pb_stream r_sa_pbs; - struct isakmp_sa sa = sapd->payload.sa; - - /* sa header is unchanged -- except for np */ - sa.isasa_np = ISAKMP_NEXT_NONCE; - if (!out_struct(&sa, &isakmp_sa_desc, &md->rbody, &r_sa_pbs)) - { - return STF_INTERNAL_ERROR; - } - - /* parse and accept body */ - st->st_pfs_group = &unset_group; - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sapd->pbs - , &sapd->payload.sa, &r_sa_pbs, FALSE, st)); - } - - passert(st->st_pfs_group != &unset_group); - - if ((st->st_policy & POLICY_PFS) && st->st_pfs_group == NULL) - { - loglog(RC_LOG_SERIOUS, "we require PFS but Quick I1 SA specifies no GROUP_DESCRIPTION"); - return STF_FAIL + ISAKMP_NO_PROPOSAL_CHOSEN; - } - - /* Ni in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_ni, "Ni")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gi, "Gi", "Quick Mode I1")); - - plog("responding to Quick Mode"); - - /**** finish reply packet: Nr [, KE ] [, IDci, IDcr ] ****/ - - /* Nr out */ - if (!build_and_ship_nonce(&st->st_nr, &md->rbody - , st->st_pfs_group != NULL? ISAKMP_NEXT_KE : id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE - , "Nr")) - { - return STF_INTERNAL_ERROR; - } - - /* [ KE ] out (for PFS) */ - - if (st->st_pfs_group != NULL) - { - if (!build_and_ship_KE(st, &st->st_gr, st->st_pfs_group - , &md->rbody, id_pd != NULL? ISAKMP_NEXT_ID : ISAKMP_NEXT_NONE)) - { - return STF_INTERNAL_ERROR; - } - - /* MPZ-Operations might be done after sending the packet... */ - compute_dh_shared(st, st->st_gi); - } - - /* [ IDci, IDcr ] out */ - if (id_pd != NULL) - { - struct isakmp_ipsec_id *p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->pbs.start, pbs_room(&id_pd->pbs), &md->rbody, "IDci")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_ID; - - p = (void *)md->rbody.cur; /* UGH! */ - - if (!out_raw(id_pd->next->pbs.start, pbs_room(&id_pd->next->pbs), &md->rbody, "IDcr")) - { - return STF_INTERNAL_ERROR; - } - p->isaiid_np = ISAKMP_NEXT_NONE; - } - - if ((st->nat_traversal & NAT_T_WITH_NATOA) - && (st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT)) - { - /** Send NAT-OA if our address is NATed and if we use Transport Mode */ - if (!nat_traversal_add_natoa(ISAKMP_NEXT_NONE, &md->rbody, md->st)) - { - return STF_INTERNAL_ERROR; - } - } - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TRANSPORT) - && (c->spd.that.has_client)) - { - /** Remove client **/ - addrtosubnet(&c->spd.that.host_addr, &c->spd.that.client); - c->spd.that.has_client = FALSE; - } - - /* Compute reply HASH(2) and insert in output */ - (void)quick_mode_hash12(r_hashval, r_hash_start, md->rbody.cur - , st, &st->st_msgid, TRUE); - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the new inbound SA - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_inbound_ipsec_sa(st)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - - return STF_OK; - } -} - -/* - * Initialize RFC 3706 Dead Peer Detection - */ -static void dpd_init(struct state *st) -{ - struct state *p1st = find_state(st->st_icookie, st->st_rcookie - , &st->st_connection->spd.that.host_addr, 0); - - if (p1st == NULL) - { - loglog(RC_LOG_SERIOUS, "could not find phase 1 state for DPD"); - } - else if (p1st->st_dpd) - { - plog("Dead Peer Detection (RFC 3706) enabled"); - /* randomize the first DPD event */ - - event_schedule(EVENT_DPD - , (0.5 + rand()/(RAND_MAX + 1.E0)) * st->st_connection->dpd_delay - , st); - } -} - -/* Handle (the single) message from Responder in Quick Mode. - * HDR*, HASH(2), SA, Nr [, KE ] [, IDci, IDcr ] --> - * HDR*, HASH(3) - * (see RFC 2409 "IKE" 5.5) - * Installs inbound and outbound IPsec SAs, routing, etc. - */ -stf_status quick_inR1_outI2(struct msg_digest *md) -{ - enum endpoint ep = EP_LOCAL | EP_REMOTE; - struct state *const st = md->st; - const connection_t *c = st->st_connection; - - /* HASH(2) in */ - CHECK_QUICK_HASH(md - , quick_mode_hash12(hash_val, hash_pbs->roof, md->message_pbs.roof - , st, &st->st_msgid, TRUE) - , "HASH(2)", "Quick R1"); - - /* SA in */ - { - struct payload_digest *const sa_pd = md->chain[ISAKMP_NEXT_SA]; - - RETURN_STF_FAILURE(parse_ipsec_sa_body(&sa_pd->pbs - , &sa_pd->payload.sa, NULL, TRUE, st)); - } - - /* Nr in */ - RETURN_STF_FAILURE(accept_nonce(md, &st->st_nr, "Nr")); - - /* [ KE ] in (for PFS) */ - RETURN_STF_FAILURE(accept_PFS_KE(md, &st->st_gr, "Gr", "Quick Mode R1")); - - if (st->st_pfs_group != NULL) - { - compute_dh_shared(st, st->st_gr); - } - - /* [ IDci, IDcr ] in; these must match what we sent */ - - { - struct payload_digest *const id_pd = md->chain[ISAKMP_NEXT_ID]; - - if (id_pd != NULL) - { - /* ??? we are assuming IPSEC_DOI */ - - /* IDci (we are initiator) */ - - if (!check_net_id(&id_pd->payload.ipsec_id, &id_pd->pbs - , &st->st_myuserprotoid, &st->st_myuserport - , &st->st_connection->spd.this.client - , "our client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - - /* IDcr (responder is peer) */ - - if (!check_net_id(&id_pd->next->payload.ipsec_id, &id_pd->next->pbs - , &st->st_peeruserprotoid, &st->st_peeruserport - , &st->st_connection->spd.that.client - , "peer client")) - { - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - else - { - /* no IDci, IDcr: we must check that the defaults match our proposal */ - if (!subnetisaddr(&c->spd.this.client, &c->spd.this.host_addr) - || !subnetisaddr(&c->spd.that.client, &c->spd.that.host_addr)) - { - loglog(RC_LOG_SERIOUS, "IDci, IDcr payloads missing in message" - " but default does not match proposal"); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - } - - /* check the peer's group attributes */ - { - identification_t *peer_ca = NULL; - ietf_attributes_t *peer_attributes = NULL; - bool match; - - get_peer_ca_and_groups(st->st_connection, &peer_ca, &peer_attributes); - match = match_group_membership(peer_attributes, - st->st_connection->name, - st->st_connection->spd.that.groups); - DESTROY_IF(peer_attributes); - - if (!match) - { - ietf_attributes_t *groups = st->st_connection->spd.that.groups; - - loglog(RC_LOG_SERIOUS, - "peer with attributes '%s' is not a member of the groups '%s'", - peer_attributes->get_string(peer_attributes), - groups->get_string(groups)); - return STF_FAIL + ISAKMP_INVALID_ID_INFORMATION; - } - } - - if ((st->nat_traversal & NAT_T_DETECTED) - && (st->nat_traversal & NAT_T_WITH_NATOA)) - { - nat_traversal_natoa_lookup(md); - } - - /* ??? We used to copy the accepted proposal into the state, but it was - * never used. From sa_pd->pbs.start, length pbs_room(&sa_pd->pbs). - */ - - /**************** build reply packet HDR*, HASH(3) ****************/ - - /* HDR* out done */ - - /* HASH(3) out -- since this is the only content, no passes needed */ - { - u_char /* set by START_HASH_PAYLOAD: */ - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - START_HASH_PAYLOAD(md->rbody, ISAKMP_NEXT_NONE); - (void)quick_mode_hash3(r_hashval, st); - } - - /* Derive new keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the inbound, outbound, and routing part - * of the new SA (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, TRUE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - /* encrypt message, except for fixed part of header */ - - if (!encrypt_message(&md->rbody, st)) - { - return STF_INTERNAL_ERROR; /* ??? we may be partly committed */ - } - DBG(DBG_CONTROLMORE, - DBG_log("inR1_outI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - /* note (presumed) success */ - if (c->gw_info != NULL) - { - c->gw_info->key->last_worked_time = now(); - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -/* Handle last message of Quick Mode. - * HDR*, HASH(3) -> done - * (see RFC 2409 "IKE" 5.5) - * Installs outbound IPsec SAs, routing, etc. - */ -stf_status quick_inI2(struct msg_digest *md) -{ - enum endpoint ep = EP_REMOTE; - struct state *const st = md->st; - - /* HASH(3) in */ - CHECK_QUICK_HASH(md, quick_mode_hash3(hash_val, st) - , "HASH(3)", "Quick I2"); - - /* Derive keying material */ - compute_keymats(st, ep); - - /* Tell the kernel to establish the outbound and routing part of the new SA - * (the previous state established inbound) - * (unless the commit bit is set -- which we don't support). - * We do this before any state updating so that - * failure won't look like success. - */ - if (!install_ipsec_sa(st, FALSE)) - { - wipe_keymats(st, ep); - return STF_INTERNAL_ERROR; - } - wipe_keymats(st, ep); - - DBG(DBG_CONTROLMORE, - DBG_log("inI2: instance %s[%ld], setting newest_ipsec_sa to #%ld (was #%ld) (spd.eroute=#%ld)" - , st->st_connection->name - , st->st_connection->instance_serial - , st->st_serialno - , st->st_connection->newest_ipsec_sa - , st->st_connection->spd.eroute_owner) - ) - st->st_connection->newest_ipsec_sa = st->st_serialno; - - update_iv(st); /* not actually used, but tidy */ - - /* note (presumed) success */ - { - struct gw_info *gw = st->st_connection->gw_info; - - if (gw != NULL) - { - gw->key->last_worked_time = now(); - } - } - - /* If we want DPD on this connection then initialize it */ - if (st->st_connection->dpd_action != DPD_ACTION_NONE) - { - dpd_init(st); - } - return STF_OK; -} - -static stf_status send_isakmp_notification(struct state *st, u_int16_t type, - const void *data, size_t len) -{ - msgid_t msgid; - pb_stream reply; - pb_stream rbody; - u_char - *r_hashval, /* where in reply to jam hash value */ - *r_hash_start; /* start of what is to be hashed */ - - msgid = generate_msgid(st); - - init_pbs(&reply, reply_buffer, sizeof(reply_buffer), "ISAKMP notify"); - - /* HDR* */ - { - struct isakmp_hdr hdr; - - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_INFO; - hdr.isa_msgid = msgid; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody)) - { - impossible(); - } - } - /* HASH -- create and note space to be filled later */ - START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_N); - - /* NOTIFY */ - { - pb_stream notify_pbs; - struct isakmp_notification isan; - - isan.isan_np = ISAKMP_NEXT_NONE; - isan.isan_doi = ISAKMP_DOI_IPSEC; - isan.isan_protoid = PROTO_ISAKMP; - isan.isan_spisize = COOKIE_SIZE * 2; - isan.isan_type = type; - if (!out_struct(&isan, &isakmp_notification_desc, &rbody, ¬ify_pbs)) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_icookie, COOKIE_SIZE, ¬ify_pbs, "notify icookie")) - { - return STF_INTERNAL_ERROR; - } - if (!out_raw(st->st_rcookie, COOKIE_SIZE, ¬ify_pbs, "notify rcookie")) - { - return STF_INTERNAL_ERROR; - } - if (data != NULL && len > 0) - { - if (!out_raw(data, len, ¬ify_pbs, "notify data")) - { - return STF_INTERNAL_ERROR; - } - } - close_output_pbs(¬ify_pbs); - } - - { - /* finish computing HASH */ - chunk_t msgid_chunk = chunk_from_thing(msgid); - chunk_t msg_chunk = { r_hash_start, rbody.cur-r_hash_start }; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, r_hashval); - - DBG(DBG_CRYPT, - DBG_log("HASH computed:"); - DBG_dump("", r_hashval, prf->get_block_size(prf)); - ) - prf->destroy(prf); - } - - /* Encrypt message (preserve st_iv and st_new_iv) */ - { - u_char old_iv[MAX_DIGEST_LEN]; - u_char new_iv[MAX_DIGEST_LEN]; - - u_int old_iv_len = st->st_iv_len; - u_int new_iv_len = st->st_new_iv_len; - - if (old_iv_len > MAX_DIGEST_LEN || new_iv_len > MAX_DIGEST_LEN) - return STF_INTERNAL_ERROR; - - memcpy(old_iv, st->st_iv, old_iv_len); - memcpy(new_iv, st->st_new_iv, new_iv_len); - - init_phase2_iv(st, &msgid); - if (!encrypt_message(&rbody, st)) - { - return STF_INTERNAL_ERROR; - } - - /* restore preserved st_iv and st_new_iv */ - memcpy(st->st_iv, old_iv, old_iv_len); - memcpy(st->st_new_iv, new_iv, new_iv_len); - st->st_iv_len = old_iv_len; - st->st_new_iv_len = new_iv_len; - } - - /* Send packet (preserve st_tpacket) */ - { - chunk_t saved_tpacket = st->st_tpacket; - - st->st_tpacket = chunk_create(reply.start, pbs_offset(&reply)); - send_packet(st, "ISAKMP notify"); - st->st_tpacket = saved_tpacket; - } - - return STF_IGNORE; -} - -/* - * DPD Out Initiator - */ -void dpd_outI(struct state *p2st) -{ - struct state *st; - u_int32_t seqno; - time_t tm; - time_t idle_time; - time_t delay = p2st->st_connection->dpd_delay; - time_t timeout = p2st->st_connection->dpd_timeout; - - /* find the newest related Phase 1 state */ - st = find_phase1_state(p2st->st_connection, ISAKMP_SA_ESTABLISHED_STATES); - - if (st == NULL) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not find newest phase 1 state"); - return; - } - - /* If no DPD, then get out of here */ - if (!st->st_dpd) - { - return; - } - - /* schedule the next periodic DPD event */ - event_schedule(EVENT_DPD, delay, p2st); - - /* Current time */ - tm = now(); - - /* Make sure we really need to invoke DPD */ - if (!was_eroute_idle(p2st, delay, &idle_time)) - { - DBG(DBG_CONTROL, - DBG_log("recent eroute activity %u seconds ago, " - "no need to send DPD notification" - , (int)idle_time) - ) - st->st_last_dpd = tm; - delete_dpd_event(st); - return; - } - - /* If an R_U_THERE has been sent or received recently, or if a - * companion Phase 2 SA has shown eroute activity, - * then we don't need to invoke DPD. - */ - if (tm < st->st_last_dpd + delay) - { - DBG(DBG_CONTROL, - DBG_log("recent DPD activity %u seconds ago, " - "no need to send DPD notification" - , (int)(tm - st->st_last_dpd)) - ) - return; - } - - if (!IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - return; - - if (!st->st_dpd_seqno) - { - rng_t *rng; - - /* Get a non-zero random value that has room to grow */ - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->get_bytes(rng, sizeof(st->st_dpd_seqno), (u_char *)&st->st_dpd_seqno); - rng->destroy(rng); - st->st_dpd_seqno &= 0x7fff; - st->st_dpd_seqno++; - } - seqno = htonl(st->st_dpd_seqno); - - if (send_isakmp_notification(st, R_U_THERE, &seqno, sizeof(seqno)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD: Could not send R_U_THERE"); - return; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE with seqno = %u", st->st_dpd_seqno) - ) - st->st_dpd_expectseqno = st->st_dpd_seqno++; - st->st_last_dpd = tm; - /* Only schedule a new timeout if there isn't one currently, - * or if it would be sooner than the current timeout. */ - if (st->st_dpd_event == NULL - || st->st_dpd_event->ev_time > tm + timeout) - { - delete_dpd_event(st); - event_schedule(EVENT_DPD_TIMEOUT, timeout, st); - } -} - -/* - * DPD in Initiator, out Responder - */ -stf_status -dpd_inI_outR(struct state *st, struct isakmp_notification *const n, pb_stream *pbs) -{ - time_t tm = now(); - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS, "DPD: Received R_U_THERE for unestablished ISAKMP SA"); - return STF_IGNORE; - } - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid SPI length (%d)", n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid icookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid rcookie (broken Cisco?)"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE with seqno = %u", seqno) - ) - - if (st->st_dpd_peerseqno && seqno <= st->st_dpd_peerseqno) { - loglog(RC_LOG_SERIOUS, "DPD: Received old or duplicate R_U_THERE"); - return STF_IGNORE; - } - - st->st_dpd_peerseqno = seqno; - delete_dpd_event(st); - - if (send_isakmp_notification(st, R_U_THERE_ACK, pbs->cur, pbs_left(pbs)) != STF_IGNORE) - { - loglog(RC_LOG_SERIOUS, "DPD Info: could not send R_U_THERE_ACK"); - return STF_IGNORE; - } - DBG(DBG_CONTROL, - DBG_log("sent DPD notification R_U_THERE_ACK with seqno = %u", seqno) - ) - - st->st_last_dpd = tm; - return STF_IGNORE; -} - -/* - * DPD out Responder - */ -stf_status dpd_inR(struct state *st, struct isakmp_notification *const n, - pb_stream *pbs) -{ - u_int32_t seqno; - - if (st == NULL || !IS_ISAKMP_SA_ESTABLISHED(st->st_state)) - { - loglog(RC_LOG_SERIOUS - , "DPD: Received R_U_THERE_ACK for unestablished ISAKMP SA"); - return STF_FAIL; - } - - if (n->isan_spisize != COOKIE_SIZE * 2 || pbs_left(pbs) < COOKIE_SIZE * 2) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has invalid SPI length (%d)" - , n->isan_spisize); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - if (memcmp(pbs->cur, st->st_icookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid icookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (memcmp(pbs->cur, st->st_rcookie, COOKIE_SIZE) != 0) - { -#ifdef APPLY_CRISCO - /* Ignore it, cisco sends odd icookies */ -#else - loglog(RC_LOG_SERIOUS, "DPD: R_U_THERE_ACK has invalid rcookie"); - return STF_FAIL + ISAKMP_INVALID_COOKIE; -#endif - } - pbs->cur += COOKIE_SIZE; - - if (pbs_left(pbs) != sizeof(seqno)) - { - loglog(RC_LOG_SERIOUS - , " DPD: R_U_THERE_ACK has invalid data length (%d)" - , (int) pbs_left(pbs)); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - seqno = ntohl(*(u_int32_t *)pbs->cur); - DBG(DBG_CONTROL, - DBG_log("received DPD notification R_U_THERE_ACK with seqno = %u" - , seqno) - ) - - if (!st->st_dpd_expectseqno && seqno != st->st_dpd_expectseqno) - { - loglog(RC_LOG_SERIOUS - , "DPD: R_U_THERE_ACK has unexpected sequence number %u (expected %u)" - , seqno, st->st_dpd_expectseqno); - return STF_FAIL + ISAKMP_PAYLOAD_MALFORMED; - } - - st->st_dpd_expectseqno = 0; - delete_dpd_event(st); - return STF_IGNORE; -} - -/* - * DPD Timeout Function - * - * This function is called when a timeout DPD_EVENT occurs. We set clear/trap - * both the SA and the eroutes, depending on what the connection definition - * tells us (either 'hold' or 'clear') - */ -void -dpd_timeout(struct state *st) -{ - struct state *newest_phase1_st; - connection_t *c = st->st_connection; - int action = st->st_connection->dpd_action; - char cname[BUF_LEN]; - - passert(action == DPD_ACTION_HOLD - || action == DPD_ACTION_CLEAR - || DPD_ACTION_RESTART); - - /* is there a newer phase1_state? */ - newest_phase1_st = find_phase1_state(c, ISAKMP_SA_ESTABLISHED_STATES); - if (newest_phase1_st != NULL && newest_phase1_st != st) - { - plog("DPD: Phase1 state #%ld has been superseded by #%ld" - " - timeout ignored" - , st->st_serialno, newest_phase1_st->st_serialno); - return; - } - - loglog(RC_LOG_SERIOUS, "DPD: No response from peer - declaring peer dead"); - - /* delete the state, which is probably in phase 2 */ - set_cur_connection(c); - plog("DPD: Terminating all SAs using this connection"); - delete_states_by_connection(c, TRUE); - reset_cur_connection(); - - switch (action) - { - case DPD_ACTION_HOLD: - /* dpdaction=hold - Wipe the SA's but %trap the eroute so we don't - * leak traffic. Also, being in %trap means new packets will - * force an initiation of the conn again. - */ - loglog(RC_LOG_SERIOUS, "DPD: Putting connection \"%s\" into %%trap", c->name); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_CLEAR: - /* dpdaction=clear - Wipe the SA & eroute - everything */ - loglog(RC_LOG_SERIOUS, "DPD: Clearing connection \"%s\"", c->name); - unroute_connection(c); - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - break; - case DPD_ACTION_RESTART: - /* dpdaction=restart - Restart connection, - * except if roadwarrior connection - */ - loglog(RC_LOG_SERIOUS, "DPD: Restarting connection \"%s\"", c->name); - unroute_connection(c); - - /* caching the connection name before deletion */ - strncpy(cname, c->name, BUF_LEN); - cname[BUF_LEN-1] = '\0'; - - if (c->kind == CK_INSTANCE) - { - delete_connection(c, TRUE); - } - initiate_connection(cname, NULL_FD); - break; - default: - loglog(RC_LOG_SERIOUS, "DPD: unknown action"); - } -} - diff --git a/src/pluto/ipsec_doi.h b/src/pluto/ipsec_doi.h deleted file mode 100644 index c11edaa94..000000000 --- a/src/pluto/ipsec_doi.h +++ /dev/null @@ -1,108 +0,0 @@ -/* IPsec DOI and Oakley resolution routines - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _IPSEC_DOI_H -#define _IPSEC_DOI_H - -#include "defs.h" - -extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np); - -extern void ipsecdoi_initiate(int whack_sock, struct connection *c - , lset_t policy, unsigned long try, so_serial_t replacing); - -extern void ipsecdoi_replace(struct state *st, unsigned long try); - -extern void init_phase2_iv(struct state *st, const msgid_t *msgid); - -extern stf_status quick_outI1(int whack_sock - , struct state *isakmp_sa - , struct connection *c - , lset_t policy - , unsigned long try - , so_serial_t replacing); - -extern state_transition_fn - main_inI1_outR1, - main_inR1_outI2, - main_inI2_outR2, - main_inR2_outI3, - main_inI3_outR3, - main_inR3, - quick_inI1_outR1, - quick_inR1_outI2, - quick_inI2; - -extern void send_delete(struct state *st); -extern void accept_delete(struct state *st, struct msg_digest *md - , struct payload_digest *p); -extern void close_message(pb_stream *pbs); -extern bool encrypt_message(pb_stream *pbs, struct state *st); - - -extern void send_notification_from_state(struct state *st, - enum state_kind state, u_int16_t type); -extern void send_notification_from_md(struct msg_digest *md, u_int16_t type); - -extern const char *init_pluto_vendorid(void); - -extern void dpd_outI(struct state *st); -extern stf_status dpd_inI_outR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern stf_status dpd_inR(struct state *st - , struct isakmp_notification *const n, pb_stream *n_pbs); -extern void dpd_timeout(struct state *st); - -/* START_HASH_PAYLOAD - * - * Emit a to-be-filled-in hash payload, noting the field start (r_hashval) - * and the start of the part of the message to be hashed (r_hash_start). - * This macro is magic. - * - it can cause the caller to return - * - it references variables local to the caller (r_hashval, r_hash_start, st) - */ -#define START_HASH_PAYLOAD(rbody, np) { \ - pb_stream hash_pbs; \ - if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \ - return STF_INTERNAL_ERROR; \ - r_hashval = hash_pbs.cur; /* remember where to plant value */ \ - if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \ - return STF_INTERNAL_ERROR; \ - close_output_pbs(&hash_pbs); \ - r_hash_start = (rbody).cur; /* hash from after HASH payload */ \ -} - -/* CHECK_QUICK_HASH - * - * This macro is magic -- it cannot be expressed as a function. - * - it causes the caller to return! - * - it declares local variables and expects the "do_hash" argument - * expression to reference them (hash_val, hash_pbs) - */ -#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \ - pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \ - u_char hash_val[MAX_DIGEST_LEN]; \ - size_t hash_len = do_hash; \ - if (pbs_left(hash_pbs) != hash_len \ - || memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \ - { \ - DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \ - loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \ - /* XXX Could send notification back */ \ - return STF_FAIL + ISAKMP_INVALID_HASH_INFORMATION; \ - } \ - } - -#endif /* _IPSEC_DOI_H */ - diff --git a/src/pluto/kameipsec.h b/src/pluto/kameipsec.h deleted file mode 100644 index 5e9d8ce99..000000000 --- a/src/pluto/kameipsec.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __IPSEC_H -#define __IPSEC_H 1 - -/* The definitions, required to talk to KAME racoon IKE. */ - -#define IPSEC_PORT_ANY 0 -#define IPSEC_ULPROTO_ANY 255 -#define IPSEC_PROTO_ANY 255 - -enum { - IPSEC_MODE_ANY = 0, /* We do not support this for SA */ - IPSEC_MODE_TRANSPORT = 1, - IPSEC_MODE_TUNNEL = 2 -}; - -enum { - IPSEC_DIR_ANY = 0, - IPSEC_DIR_INBOUND = 1, - IPSEC_DIR_OUTBOUND = 2, - IPSEC_DIR_FWD = 3, /* It is our own */ - IPSEC_DIR_MAX = 4, - IPSEC_DIR_INVALID = 5 -}; - -enum { - IPSEC_POLICY_DISCARD = 0, - IPSEC_POLICY_NONE = 1, - IPSEC_POLICY_IPSEC = 2, - IPSEC_POLICY_ENTRUST = 3, - IPSEC_POLICY_BYPASS = 4 -}; - -enum { - IPSEC_LEVEL_DEFAULT = 0, - IPSEC_LEVEL_USE = 1, - IPSEC_LEVEL_REQUIRE = 2, - IPSEC_LEVEL_UNIQUE = 3 -}; - -#define IPSEC_MANUAL_REQID_MAX 0x3fff - -#define IPSEC_REPLAYWSIZE 32 - -#define IP_IPSEC_POLICY 16 -#define IPV6_IPSEC_POLICY 34 - -#endif /* __IPSEC_H */ diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c deleted file mode 100644 index e4729ef08..000000000 --- a/src/pluto/kernel.c +++ /dev/null @@ -1,2114 +0,0 @@ -/* routines that interface with the kernel's IPsec mechanism - * - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * Copyright (C) 1998-2002 D. Hugh Redelmeier - * Copyright (C) 1997 Angelos D. Keromytis - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include /* for select(2) */ -#include /* for select(2) */ -#include -#include -#include "kameipsec.h" - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "timer.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "ca.h" -#include "server.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "keys.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "alg_info.h" -#include "kernel_alg.h" -#include "pluto.h" - - -bool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? */ - -/* test if the routes required for two different connections agree - * It is assumed that the destination subnets agree; we are only - * testing that the interfaces and nexthops match. - */ -#define routes_agree(c, d) ((c)->interface == (d)->interface \ - && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop)) - -/* forward declaration */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, unsigned int op, - const char *opname); - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto); - -/** - * Default IPsec SA config (e.g. to install trap policies). - */ -static ipsec_sa_cfg_t null_ipsec_sa = { - .mode = MODE_TRANSPORT, - .esp = { - .use = TRUE, - }, -}; - -/** - * Helper function that converts an ip_subnet to a traffic_selector_t. - */ -static traffic_selector_t *traffic_selector_from_subnet(const ip_subnet *client, - const u_int8_t proto) -{ - traffic_selector_t *ts; - host_t *net; - net = host_create_from_sockaddr((sockaddr_t*)&client->addr); - ts = traffic_selector_create_from_subnet(net, client->maskbits, proto, - net->get_port(net)); - return ts; -} - -/** - * Helper function that converts a traffic_selector_t to an ip_subnet. - */ -static ip_subnet subnet_from_traffic_selector(traffic_selector_t *ts) -{ - ip_subnet subnet; - host_t *net; - u_int8_t mask; - ts->to_subnet(ts, &net, &mask); - subnet.addr = *(ip_address*)net->get_sockaddr(net); - subnet.maskbits = mask; - net->destroy(net); - return subnet; -} - - -void record_and_initiate_opportunistic(const ip_subnet *ours, - const ip_subnet *his, - int transport_proto, const char *why) -{ - ip_address src, dst; - passert(samesubnettype(ours, his)); - - /* actually initiate opportunism */ - networkof(ours, &src); - networkof(his, &dst); - initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD); -} - -/* Generate Unique SPI numbers. - * - * The returned SPI is in network byte order. - */ -ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, - bool tunnel) -{ - host_t *host_src, *host_dst; - u_int32_t spi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_spi(hydra->kernel_interface, host_src, - host_dst, proto, sr->reqid, &spi) != SUCCESS) - { - spi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return spi; -} - -/* Generate Unique CPI numbers. - * The result is returned as an SPI (4 bytes) in network order! - * The real bits are in the nework-low-order 2 bytes. - */ -ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel) -{ - host_t *host_src, *host_dst; - u_int16_t cpi; - - host_src = host_create_from_sockaddr((sockaddr_t*)&sr->that.host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&sr->this.host_addr); - - if (hydra->kernel_interface->get_cpi(hydra->kernel_interface, host_src, - host_dst, sr->reqid, &cpi) != SUCCESS) - - { - cpi = 0; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return htonl((u_int32_t)ntohs(cpi)); -} - -/* Replace the shell metacharacters ', \, ", `, and $ in a character string - * by escape sequences consisting of their octal values - */ -static void escape_metachar(const char *src, char *dst, size_t dstlen) -{ - while (*src != '\0' && dstlen > 4) - { - switch (*src) - { - case '\'': - case '\\': - case '"': - case '`': - case '$': - sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src); - dst += 4; - dstlen -= 4; - break; - default: - *dst++ = *src; - dstlen--; - } - src++; - } - *dst = '\0'; -} - -/* invoke the updown script to do the routing and firewall commands required - * - * The user-specified updown script is run. Parameters are fed to it in - * the form of environment variables. All such environment variables - * have names starting with "PLUTO_". - * - * The operation to be performed is specified by PLUTO_VERB. This - * verb has a suffix "-host" if the client on this end is just the - * host; otherwise the suffix is "-client". If the address family - * of the host is IPv6, an extra suffix of "-v6" is added. - * - * "prepare-host" and "prepare-client" are used to delete a route - * that may exist (due to forces outside of Pluto). It is used to - * prepare for pluto creating a route. - * - * "route-host" and "route-client" are used to install a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "unroute-host" and "unroute-client" are used to delete a route. - * Since routing is based only on destination, the PLUTO_MY_CLIENT_* - * values are probably of no use (using them may signify a bug). - * - * "up-host" and "up-client" are run when an eroute is added (not replaced). - * They are useful for adjusting a firewall: usually for adding a rule - * to let processed packets flow between clients. Note that only - * one eroute may exist for a pair of client subnets but inbound - * IPsec SAs may persist without an eroute. - * - * "down-host" and "down-client" are run when an eroute is deleted. - * They are useful for adjusting a firewall. - */ - -#ifndef DEFAULT_UPDOWN -# define DEFAULT_UPDOWN "ipsec _updown" -#endif - -static bool do_command(connection_t *c, struct spd_route *sr, struct state *st, - const char *verb) -{ - char cmd[1536]; /* arbitrary limit on shell command length */ - const char *verb_suffix; - - /* figure out which verb suffix applies */ - { - const char *hs, *cs; - - switch (addrtypeof(&sr->this.host_addr)) - { - case AF_INET: - hs = "-host"; - cs = "-client"; - break; - case AF_INET6: - hs = "-host-v6"; - cs = "-client-v6"; - break; - default: - loglog(RC_LOG_SERIOUS, "unknown address family"); - return FALSE; - } - verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr) - ? hs : cs; - } - - /* form the command string */ - { - char - nexthop_str[sizeof("PLUTO_NEXT_HOP='' ") +ADDRTOT_BUF] = "", - srcip_str[sizeof("PLUTO_MY_SOURCEIP='' ")+ADDRTOT_BUF] = "", - me_str[ADDRTOT_BUF], - myid_str[BUF_LEN], - myclient_str[SUBNETTOT_BUF], - myclientnet_str[ADDRTOT_BUF], - myclientmask_str[ADDRTOT_BUF], - peer_str[ADDRTOT_BUF], - peerid_str[BUF_LEN], - peerclient_str[SUBNETTOT_BUF], - peerclientnet_str[ADDRTOT_BUF], - peerclientmask_str[ADDRTOT_BUF], - peerca_str[BUF_LEN], - mark_in[BUF_LEN] = "", - mark_out[BUF_LEN] = "", - udp_encap[BUF_LEN] = "", - xauth_id_str[BUF_LEN] = "", - secure_myid_str[BUF_LEN] = "", - secure_peerid_str[BUF_LEN] = "", - secure_peerca_str[BUF_LEN] = "", - secure_xauth_id_str[BUF_LEN] = ""; - ip_address ta; - pubkey_list_t *p; - - if (addrbytesptr(&sr->this.host_nexthop, NULL) - && !isanyaddr(&sr->this.host_nexthop)) - { - char *n; - - strcpy(nexthop_str, "PLUTO_NEXT_HOP='"); - n = nexthop_str + strlen(nexthop_str); - - addrtot(&sr->this.host_nexthop, 0 - ,n , sizeof(nexthop_str)-strlen(nexthop_str)); - strncat(nexthop_str, "' ", sizeof(nexthop_str)); - } - - if (!sr->this.host_srcip->is_anyaddr(sr->this.host_srcip)) - { - char *n; - - strcpy(srcip_str, "PLUTO_MY_SOURCEIP='"); - n = srcip_str + strlen(srcip_str); - snprintf(n, sizeof(srcip_str)-strlen(srcip_str), "%H", - sr->this.host_srcip); - strncat(srcip_str, "' ", sizeof(srcip_str)); - } - - if (sr->mark_in.value) - { - snprintf(mark_in, sizeof(mark_in), "PLUTO_MARK_IN='%u/0x%08x' ", - sr->mark_in.value, sr->mark_in.mask); - } - - if (sr->mark_out.value) - { - snprintf(mark_out, sizeof(mark_out), "PLUTO_MARK_OUT='%u/0x%08x' ", - sr->mark_out.value, sr->mark_out.mask); - } - - if (st && (st->nat_traversal & NAT_T_DETECTED)) - { - snprintf(udp_encap, sizeof(udp_encap), "PLUTO_UDP_ENC='%u' ", - sr->that.host_port); - } - - addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); - snprintf(myid_str, sizeof(myid_str), "%Y", sr->this.id); - escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); - subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); - networkof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str)); - maskof(&sr->this.client, &ta); - addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str)); - - if (c->xauth_identity && - c->xauth_identity->get_type(c->xauth_identity) != ID_ANY) - { - snprintf(xauth_id_str, sizeof(xauth_id_str), "%Y", c->xauth_identity); - escape_metachar(xauth_id_str, secure_xauth_id_str, - sizeof(secure_xauth_id_str)); - snprintf(xauth_id_str, sizeof(xauth_id_str), "PLUTO_XAUTH_ID='%s' ", - secure_xauth_id_str); - } - - addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); - snprintf(peerid_str, sizeof(peerid_str), "%Y", sr->that.id); - escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); - subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); - networkof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str)); - maskof(&sr->that.client, &ta); - addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str)); - - for (p = pubkeys; p != NULL; p = p->next) - { - pubkey_t *key = p->key; - key_type_t type = key->public_key->get_type(key->public_key); - int pathlen; - - if (type == KEY_RSA && - sr->that.id->equals(sr->that.id, key->id) && - trusted_ca(key->issuer, sr->that.ca, &pathlen)) - { - if (key->issuer) - { - snprintf(peerca_str, BUF_LEN, "%Y", key->issuer); - escape_metachar(peerca_str, secure_peerca_str, BUF_LEN); - } - else - { - secure_peerca_str[0] = '\0'; - } - break; - } - } - - if (-1 == snprintf(cmd, sizeof(cmd) - , "2>&1 " /* capture stderr along with stdout */ - "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */ - "PLUTO_VERB='%s%s' " - "PLUTO_CONNECTION='%s' " - "%s" /* optional PLUTO_NEXT_HOP */ - "PLUTO_INTERFACE='%s' " - "%s" /* optional PLUTO_HOST_ACCESS */ - "PLUTO_REQID='%u' " - "PLUTO_ME='%s' " - "PLUTO_MY_ID='%s' " - "PLUTO_MY_CLIENT='%s' " - "PLUTO_MY_CLIENT_NET='%s' " - "PLUTO_MY_CLIENT_MASK='%s' " - "PLUTO_MY_PORT='%u' " - "PLUTO_MY_PROTOCOL='%u' " - "PLUTO_PEER='%s' " - "PLUTO_PEER_ID='%s' " - "PLUTO_PEER_CLIENT='%s' " - "PLUTO_PEER_CLIENT_NET='%s' " - "PLUTO_PEER_CLIENT_MASK='%s' " - "PLUTO_PEER_PORT='%u' " - "PLUTO_PEER_PROTOCOL='%u' " - "PLUTO_PEER_CA='%s' " - "%s" /* optional PLUTO_MY_SRCIP */ - "%s" /* optional PLUTO_XAUTH_ID */ - "%s" /* optional PLUTO_MARK_IN */ - "%s" /* optional PLUTO_MARK_OUT */ - "%s" /* optional PLUTO_UDP_ENC */ - "%s" /* actual script */ - , verb, verb_suffix - , c->name - , nexthop_str - , c->interface->vname - , sr->this.hostaccess? "PLUTO_HOST_ACCESS='1' " : "" - , sr->reqid - , me_str - , secure_myid_str - , myclient_str - , myclientnet_str - , myclientmask_str - , sr->this.port - , sr->this.protocol - , peer_str - , secure_peerid_str - , peerclient_str - , peerclientnet_str - , peerclientmask_str - , sr->that.port - , sr->that.protocol - , secure_peerca_str - , srcip_str - , xauth_id_str - , mark_in - , mark_out - , udp_encap - , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) - { - loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); - return FALSE; - } - } - - DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" - , verb, verb_suffix, cmd)); - - /* invoke the script, catching stderr and stdout - * It may be of concern that some file descriptors will - * be inherited. For the ones under our control, we - * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. - * Any used by library routines (perhaps the resolver or syslog) - * will remain. - */ - FILE *f = popen(cmd, "r"); - - if (f == NULL) - { - loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); - return FALSE; - } - - /* log any output */ - for (;;) - { - /* if response doesn't fit in this buffer, it will be folded */ - char resp[256]; - - if (fgets(resp, sizeof(resp), f) == NULL) - { - if (ferror(f)) - { - log_errno((e, "fgets failed on output of %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else - { - passert(feof(f)); - break; - } - } - else - { - char *e = resp + strlen(resp); - - if (e > resp && e[-1] == '\n') - e[-1] = '\0'; /* trim trailing '\n' */ - plog("%s%s output: %s", verb, verb_suffix, resp); - } - } - - /* report on and react to return code */ - { - int r = pclose(f); - - if (r == -1) - { - log_errno((e, "pclose failed for %s%s command" - , verb, verb_suffix)); - return FALSE; - } - else if (WIFEXITED(r)) - { - if (WEXITSTATUS(r) != 0) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" - , verb, verb_suffix, WEXITSTATUS(r)); - return FALSE; - } - } - else if (WIFSIGNALED(r)) - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" - , verb, verb_suffix, WTERMSIG(r)); - return FALSE; - } - else - { - loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" - , verb, verb_suffix, r); - return FALSE; - } - } - return TRUE; -} - -/* Check that we can route (and eroute). Diagnose if we cannot. */ - -enum routability { - route_impossible = 0, - route_easy = 1, - route_nearconflict = 2, - route_farconflict = 3 -}; - -static enum routability could_route(connection_t *c) -{ - struct spd_route *esr, *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); /* who owns our route? */ - - /* it makes no sense to route a connection that is ISAKMP-only */ - if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy)) - { - loglog(RC_ROUTE, "cannot route an ISAKMP-only connection"); - return route_impossible; - } - - /* if this is a Road Warrior template, we cannot route. - * Opportunistic template is OK. - */ - if (c->kind == CK_TEMPLATE && !(c->policy & POLICY_OPPO)) - { - loglog(RC_ROUTE, "cannot route Road Warrior template"); - return route_impossible; - } - - /* if we don't know nexthop, we cannot route */ - if (isanyaddr(&c->spd.this.host_nexthop)) - { - loglog(RC_ROUTE, "cannot route connection without knowing our nexthop"); - return route_impossible; - } - - /* if routing would affect IKE messages, reject */ - if (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT - && c->spd.this.host_port != IKE_UDP_PORT - && addrinsubnet(&c->spd.that.host_addr, &c->spd.that.client)) - { - loglog(RC_LOG_SERIOUS, "cannot install route: peer is within its client"); - return route_impossible; - } - - /* If there is already a route for peer's client subnet - * and it disagrees about interface or nexthop, we cannot steal it. - * Note: if this connection is already routed (perhaps for another - * state object), the route will agree. - * This is as it should be -- it will arise during rekeying. - */ - if (ro != NULL && !routes_agree(ro, c)) - { - loglog(RC_LOG_SERIOUS, "cannot route -- route already in use for \"%s\"" - , ro->name); - return route_impossible; /* another connection already - using the eroute */ - } - - /* if there is an eroute for another connection, there is a problem */ - if (ero != NULL && ero != c) - { - connection_t *ero2, *ero_top; - connection_t *inside, *outside; - - /* - * note, wavesec (PERMANENT) goes *outside* and - * OE goes *inside* (TEMPLATE) - */ - inside = NULL; - outside= NULL; - if (ero->kind == CK_PERMANENT - && c->kind == CK_TEMPLATE) - { - outside = ero; - inside = c; - } - else if (c->kind == CK_PERMANENT - && ero->kind == CK_TEMPLATE) - { - outside = c; - inside = ero; - } - - /* okay, check again, with correct order */ - if (outside && outside->kind == CK_PERMANENT - && inside && inside->kind == CK_TEMPLATE) - { - char inst[CONN_INST_BUF]; - - /* this is a co-terminal attempt of the "near" kind. */ - /* when chaining, we chain from inside to outside */ - - /* XXX permit multiple deep connections? */ - passert(inside->policy_next == NULL); - - inside->policy_next = outside; - - /* since we are going to steal the eroute from the secondary - * policy, we need to make sure that it no longer thinks that - * it owns the eroute. - */ - outside->spd.eroute_owner = SOS_NOBODY; - outside->spd.routing = RT_UNROUTED_KEYED; - - /* set the priority of the new eroute owner to be higher - * than that of the current eroute owner - */ - inside->prio = outside->prio + 1; - - fmt_conn_instance(inside, inst); - - loglog(RC_LOG_SERIOUS - , "conflict on eroute (%s), switching eroute to %s and linking %s" - , inst, inside->name, outside->name); - - return route_nearconflict; - } - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - { - if (ero2->kind == CK_TEMPLATE - && streq(ero2->name, c->name)) - break; - } - - /* If we fell of the end of the list, then we found no TEMPLATE - * so there must be a conflict that we can't resolve. - * As the names are not equal, then we aren't replacing/rekeying. - */ - if (ero2 == NULL) - { - char inst[CONN_INST_BUF]; - - fmt_conn_instance(ero, inst); - - loglog(RC_LOG_SERIOUS - , "cannot install eroute -- it is in use for \"%s\"%s #%lu" - , ero->name, inst, esr->eroute_owner); - return route_impossible; - } - } - return route_easy; -} - -bool trap_connection(connection_t *c) -{ - switch (could_route(c)) - { - case route_impossible: - return FALSE; - - case route_nearconflict: - case route_easy: - /* RT_ROUTED_TUNNEL is treated specially: we don't override - * because we don't want to lose track of the IPSEC_SAs etc. - */ - if (c->spd.routing < RT_ROUTED_TUNNEL) - { - return route_and_eroute(c, &c->spd, NULL); - } - return TRUE; - - case route_farconflict: - return FALSE; - } - - return FALSE; -} - -/** - * Delete any eroute for a connection and unroute it if route isn't shared - */ -void unroute_connection(connection_t *c) -{ - struct spd_route *sr; - enum routing_t cr; - - for (sr = &c->spd; sr; sr = sr->next) - { - cr = sr->routing; - - if (erouted(cr)) - { - /* cannot handle a live one */ - passert(sr->routing != RT_ROUTED_TUNNEL); - shunt_eroute(c, sr, RT_UNROUTED, ERO_DELETE, "delete"); - } - - sr->routing = RT_UNROUTED; /* do now so route_owner won't find us */ - - /* only unroute if no other connection shares it */ - if (routed(cr) && route_owner(c, NULL, NULL, NULL) == NULL) - { - (void) do_command(c, sr, NULL, "unroute"); - } - } -} - - -static void set_text_said(char *text_said, const ip_address *dst, - ipsec_spi_t spi, int proto) -{ - ip_said said; - - initsaid(dst, spi, proto, &said); - satot(&said, 0, text_said, SATOT_BUF); -} - - -/** - * Setup an IPsec route entry. - * op is one of the ERO_* operators. - */ -static bool raw_eroute(const ip_address *this_host, - const ip_subnet *this_client, - const ip_address *that_host, - const ip_subnet *that_client, - mark_t mark, - ipsec_spi_t spi, - unsigned int proto, - unsigned int satype, - unsigned int transport_proto, - ipsec_sa_cfg_t *sa, - unsigned int op, - const char *opname USED_BY_DEBUG) -{ - traffic_selector_t *ts_src, *ts_dst; - host_t *host_src, *host_dst; - policy_type_t type = POLICY_IPSEC; - policy_dir_t dir = POLICY_OUT; - policy_priority_t priority = POLICY_PRIORITY_DEFAULT; - char text_said[SATOT_BUF]; - bool ok = TRUE, - deleting = (op & ERO_MASK) == ERO_DELETE, - replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT); - - set_text_said(text_said, that_host, spi, proto); - - DBG(DBG_CONTROL | DBG_KERNEL, - { - int sport = ntohs(portof(&this_client->addr)); - int dport = ntohs(portof(&that_client->addr)); - char mybuf[SUBNETTOT_BUF]; - char peerbuf[SUBNETTOT_BUF]; - - subnettot(this_client, 0, mybuf, sizeof(mybuf)); - subnettot(that_client, 0, peerbuf, sizeof(peerbuf)); - DBG_log("%s eroute %s:%d -> %s:%d => %s:%d" - , opname, mybuf, sport, peerbuf, dport - , text_said, transport_proto); - }); - - if (satype == SADB_X_SATYPE_INT) - { - switch (ntohl(spi)) - { - case SPI_PASS: - type = POLICY_PASS; - break; - case SPI_DROP: - case SPI_REJECT: - type = POLICY_DROP; - break; - case SPI_TRAP: - case SPI_TRAPSUBNET: - case SPI_HOLD: - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - return TRUE; - } - priority = POLICY_PRIORITY_ROUTED; - break; - } - } - - if (op & (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT)) - { - dir = POLICY_IN; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)this_host); - host_dst = host_create_from_sockaddr((sockaddr_t*)that_host); - ts_src = traffic_selector_from_subnet(this_client, transport_proto); - ts_dst = traffic_selector_from_subnet(that_client, transport_proto); - - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - - if (dir == POLICY_IN) - { /* handle forward policy */ - dir = POLICY_FWD; - if (deleting || replacing) - { - hydra->kernel_interface->del_policy(hydra->kernel_interface, - ts_src, ts_dst, dir, sa->reqid, mark, priority); - } - - if (!deleting && ok && - (sa->mode == MODE_TUNNEL || satype == SADB_X_SATYPE_INT)) - { - ok = hydra->kernel_interface->add_policy(hydra->kernel_interface, - host_src, host_dst, ts_src, ts_dst, dir, type, sa, - mark, priority) == SUCCESS; - } - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - ts_src->destroy(ts_src); - ts_dst->destroy(ts_dst); - - return ok; -} - -static bool eroute_connection(struct spd_route *sr, ipsec_spi_t spi, - unsigned int proto, unsigned int satype, - ipsec_sa_cfg_t *sa, unsigned int op, - const char *opname) -{ - const ip_address *peer = &sr->that.host_addr; - char buf2[256]; - bool ok; - - snprintf(buf2, sizeof(buf2) - , "eroute_connection %s", opname); - - if (proto == SA_INT) - { - peer = aftoinfo(addrtypeof(peer))->any; - } - ok = raw_eroute(peer, &sr->that.client, - &sr->this.host_addr, &sr->this.client, sr->mark_in, - spi, proto, satype, sr->this.protocol, - sa, op | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT), buf2); - return raw_eroute(&sr->this.host_addr, &sr->this.client, peer, - &sr->that.client, sr->mark_out, spi, proto, satype, - sr->this.protocol, sa, op, buf2) && ok; -} - -/* assign a bare hold to a connection */ - -bool assign_hold(connection_t *c USED_BY_DEBUG, struct spd_route *sr, - int transport_proto, - const ip_address *src, - const ip_address *dst) -{ - /* either the automatically installed %hold eroute is broad enough - * or we try to add a broader one and delete the automatic one. - * Beware: this %hold might be already handled, but still squeak - * through because of a race. - */ - enum routing_t ro = sr->routing /* routing, old */ - , rn = ro; /* routing, new */ - - passert(LHAS(LELEM(CK_PERMANENT) | LELEM(CK_INSTANCE), c->kind)); - /* figure out what routing should become */ - switch (ro) - { - case RT_UNROUTED: - rn = RT_UNROUTED_HOLD; - break; - case RT_ROUTED_PROSPECTIVE: - rn = RT_ROUTED_HOLD; - break; - default: - /* no change: this %hold is old news and should just be deleted */ - break; - } - - /* We need a broad %hold - * First we ensure that there is a broad %hold. - * There may already be one (race condition): no need to create one. - * There may already be a %trap: replace it. - * There may not be any broad eroute: add %hold. - */ - if (rn != ro) - { - if (erouted(ro) - ? !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_REPLACE, - "replace %trap with broad %hold") - : !eroute_connection(sr, htonl(SPI_HOLD), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, ERO_ADD, "add broad %hold")) - { - return FALSE; - } - } - sr->routing = rn; - return TRUE; -} - -/* install or remove eroute for SA Group */ -static bool sag_eroute(struct state *st, struct spd_route *sr, - unsigned op, const char *opname) -{ - u_int inner_proto, inner_satype; - ipsec_spi_t inner_spi = 0; - ipsec_sa_cfg_t sa = { - .mode = MODE_TRANSPORT, - }; - bool tunnel = FALSE; - - if (st->st_ah.present) - { - inner_spi = st->st_ah.attrs.spi; - inner_proto = SA_AH; - inner_satype = SADB_SATYPE_AH; - sa.ah.use = TRUE; - sa.ah.spi = inner_spi; - tunnel |= st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_esp.present) - { - inner_spi = st->st_esp.attrs.spi; - inner_proto = SA_ESP; - inner_satype = SADB_SATYPE_ESP; - sa.esp.use = TRUE; - sa.esp.spi = inner_spi; - tunnel |= st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (st->st_ipcomp.present) - { - inner_spi = st->st_ipcomp.attrs.spi; - inner_proto = SA_COMP; - inner_satype = SADB_X_SATYPE_COMP; - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - sa.ipcomp.cpi = htons(ntohl(inner_spi)); - tunnel |= st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL; - } - - if (!sa.ah.use && !sa.esp.use && !sa.ipcomp.transform) - { - impossible(); /* no transform at all! */ - } - - if (tunnel) - { - inner_spi = st->st_tunnel_out_spi; - inner_proto = SA_IPIP; - inner_satype = SADB_X_SATYPE_IPIP; - sa.mode = MODE_TUNNEL; - } - - sa.reqid = sr->reqid; - - return eroute_connection(sr, inner_spi, inner_proto, inner_satype, - &sa, op, opname); -} - -/* compute a (host-order!) SPI to implement the policy in connection c */ -ipsec_spi_t -shunt_policy_spi(connection_t *c, bool prospective) -{ - /* note: these are in host order :-( */ - static const ipsec_spi_t shunt_spi[] = - { - SPI_TRAP, /* --initiateontraffic */ - SPI_PASS, /* --pass */ - SPI_DROP, /* --drop */ - SPI_REJECT, /* --reject */ - }; - - static const ipsec_spi_t fail_spi[] = - { - 0, /* --none*/ - SPI_PASS, /* --failpass */ - SPI_DROP, /* --faildrop */ - SPI_REJECT, /* --failreject */ - }; - - return prospective - ? shunt_spi[(c->policy & POLICY_SHUNT_MASK) >> POLICY_SHUNT_SHIFT] - : fail_spi[(c->policy & POLICY_FAIL_MASK) >> POLICY_FAIL_SHIFT]; -} - -/* Add/replace/delete a shunt eroute. - * Such an eroute determines the fate of packets without the use - * of any SAs. These are defaults, in effect. - * If a negotiation has not been attempted, use %trap. - * If negotiation has failed, the choice between %trap/%pass/%drop/%reject - * is specified in the policy of connection c. - */ -static bool shunt_eroute(connection_t *c, struct spd_route *sr, - enum routing_t rt_kind, - unsigned int op, const char *opname) -{ - /* We are constructing a special SAID for the eroute. - * The destination doesn't seem to matter, but the family does. - * The protocol is SA_INT -- mark this as shunt. - * The satype has no meaning, but is required for PF_KEY header! - * The SPI signifies the kind of shunt. - */ - ipsec_spi_t spi = shunt_policy_spi(c, rt_kind == RT_ROUTED_PROSPECTIVE); - - if (spi == 0) - { - /* we're supposed to end up with no eroute: rejig op and opname */ - switch (op) - { - case ERO_REPLACE: - /* replace with nothing == delete */ - op = ERO_DELETE; - opname = "delete"; - break; - case ERO_ADD: - /* add nothing == do nothing */ - return TRUE; - case ERO_DELETE: - /* delete remains delete */ - break; - default: - bad_case(op); - } - } - if (sr->routing == RT_ROUTED_ECLIPSED && c->kind == CK_TEMPLATE) - { - /* We think that we have an eroute, but we don't. - * Adjust the request and account for eclipses. - */ - passert(eclipsable(sr)); - switch (op) - { - case ERO_REPLACE: - /* really an add */ - op = ERO_ADD; - opname = "replace eclipsed"; - eclipse_count--; - break; - case ERO_DELETE: - /* delete unnecessary: we don't actually have an eroute */ - eclipse_count--; - return TRUE; - case ERO_ADD: - default: - bad_case(op); - } - } - else if (eclipse_count > 0 && op == ERO_DELETE && eclipsable(sr)) - { - /* maybe we are uneclipsing something */ - struct spd_route *esr; - connection_t *ue = eclipsed(c, &esr); - - if (ue != NULL) - { - esr->routing = RT_ROUTED_PROSPECTIVE; - return shunt_eroute(ue, esr - , RT_ROUTED_PROSPECTIVE, ERO_REPLACE, "restoring eclipsed"); - } - } - - return eroute_connection(sr, htonl(spi), SA_INT, SADB_X_SATYPE_INT, - &null_ipsec_sa, op, opname); -} - -static bool setup_half_ipsec_sa(struct state *st, bool inbound) -{ - host_t *host_src, *host_dst; - connection_t *c = st->st_connection; - struct end *src, *dst; - ipsec_mode_t mode = MODE_TRANSPORT; - ipsec_sa_cfg_t sa = { .mode = 0 }; - lifetime_cfg_t lt_none = { .time = { .rekey = 0 } }; - mark_t mark; - bool ok = TRUE; - /* SPIs, saved for undoing, if necessary */ - struct kernel_sa said[EM_MAXRELSPIS], *said_next = said; - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL - || st->st_ipcomp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - mode = MODE_TUNNEL; - } - - sa.mode = mode; - sa.reqid = c->spd.reqid; - - memset(said, 0, sizeof(said)); - - /* set up IPCOMP SA, if any */ - - if (st->st_ipcomp.present) - { - ipsec_spi_t ipcomp_spi = inbound ? st->st_ipcomp.our_spi - : st->st_ipcomp.attrs.spi; - - switch (st->st_ipcomp.attrs.transid) - { - case IPCOMP_DEFLATE: - break; - - default: - loglog(RC_LOG_SERIOUS, "IPCOMP transform %s not implemented", - enum_name(&ipcomp_transformid_names, - st->st_ipcomp.attrs.transid)); - goto fail; - } - - sa.ipcomp.cpi = htons(ntohl(ipcomp_spi)); - sa.ipcomp.transform = st->st_ipcomp.attrs.transid; - - said_next->spi = ipcomp_spi; - said_next->proto = IPPROTO_COMP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ipcomp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - AUTH_UNDEFINED, chunk_empty, mode, - st->st_ipcomp.attrs.transid, 0 /* cpi */, FALSE, FALSE, - inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up ESP SA, if any */ - - if (st->st_esp.present) - { - ipsec_spi_t esp_spi = inbound ? st->st_esp.our_spi - : st->st_esp.attrs.spi; - u_char *esp_dst_keymat = inbound ? st->st_esp.our_keymat - : st->st_esp.peer_keymat; - bool encap = st->nat_traversal & NAT_T_DETECTED; - encryption_algorithm_t enc_alg; - integrity_algorithm_t auth_alg; - const struct esp_info *ei; - chunk_t enc_key, auth_key; - u_int16_t key_len; - - if ((ei = kernel_alg_esp_info(st->st_esp.attrs.transid, - st->st_esp.attrs.auth)) == NULL) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s / auth %s" - " not implemented yet", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - enum_name(&auth_alg_names, st->st_esp.attrs.auth)); - goto fail; - } - - key_len = st->st_esp.attrs.key_len / 8; - if (key_len) - { - /* XXX: must change to check valid _range_ key_len */ - if (key_len > ei->enckeylen) - { - loglog(RC_LOG_SERIOUS, "ESP transform %s: key_len=%d > %d", - enum_name(&esp_transform_names, st->st_esp.attrs.transid), - (int)key_len, (int)ei->enckeylen); - goto fail; - } - } - else - { - key_len = ei->enckeylen; - } - - switch (ei->transid) - { - case ESP_3DES: - /* 168 bits in kernel, need 192 bits for keymat_len */ - if (key_len == 21) - { - key_len = 24; - } - break; - case ESP_DES: - /* 56 bits in kernel, need 64 bits for keymat_len */ - if (key_len == 7) - { - key_len = 8; - } - break; - case ESP_AES_CCM_8: - case ESP_AES_CCM_12: - case ESP_AES_CCM_16: - key_len += 3; - break; - case ESP_AES_GCM_8: - case ESP_AES_GCM_12: - case ESP_AES_GCM_16: - case ESP_AES_CTR: - case ESP_AES_GMAC: - key_len += 4; - break; - default: - break; - } - - if (encap) - { - host_src->set_port(host_src, src->host_port); - host_dst->set_port(host_dst, dst->host_port); - // st->nat_oa is currently unused - } - - /* divide up keying material */ - enc_alg = encryption_algorithm_from_esp(st->st_esp.attrs.transid); - enc_key.ptr = esp_dst_keymat; - enc_key.len = key_len; - auth_alg = integrity_algorithm_from_esp(st->st_esp.attrs.auth); - auth_alg = auth_alg ? : AUTH_UNDEFINED; - auth_key.ptr = esp_dst_keymat + key_len; - auth_key.len = ei->authkeylen; - - sa.esp.use = TRUE; - sa.esp.spi = esp_spi; - - said_next->spi = esp_spi; - said_next->proto = IPPROTO_ESP; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, esp_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, enc_alg, enc_key, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - encap, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - /* set up AH SA, if any */ - - if (st->st_ah.present) - { - ipsec_spi_t ah_spi = inbound ? st->st_ah.our_spi - : st->st_ah.attrs.spi; - u_char *ah_dst_keymat = inbound ? st->st_ah.our_keymat - : st->st_ah.peer_keymat; - integrity_algorithm_t auth_alg; - chunk_t auth_key; - - auth_alg = integrity_algorithm_from_esp(st->st_ah.attrs.auth); - auth_key.ptr = ah_dst_keymat; - auth_key.len = st->st_ah.keymat_len; - - sa.ah.use = TRUE; - sa.ah.spi = ah_spi; - - said_next->spi = ah_spi; - said_next->proto = IPPROTO_AH; - - if (hydra->kernel_interface->add_sa(hydra->kernel_interface, host_src, - host_dst, ah_spi, said_next->proto, c->spd.reqid, - mark, 0, <_none, ENCR_UNDEFINED, chunk_empty, - auth_alg, auth_key, mode, IPCOMP_NONE, 0 /* cpi */, - FALSE, FALSE, inbound, NULL, NULL) != SUCCESS) - { - goto fail; - } - said_next++; - mode = MODE_TRANSPORT; - } - - goto cleanup; - -fail: - /* undo the done SPIs */ - while (said_next-- != said) - { - hydra->kernel_interface->del_sa(hydra->kernel_interface, host_src, - host_dst, said_next->spi, - said_next->proto, 0 /* cpi */, - mark); - } - ok = FALSE; - -cleanup: - host_src->destroy(host_src); - host_dst->destroy(host_dst); - return ok; -} - -static bool teardown_half_ipsec_sa(struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - const struct end *src, *dst; - host_t *host_src, *host_dst; - ipsec_spi_t spi; - mark_t mark; - bool result = TRUE; - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - if (st->st_ah.present) - { - spi = inbound ? st->st_ah.our_spi : st->st_ah.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_AH, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_esp.present) - { - spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_ESP, - 0 /* cpi */, mark) == SUCCESS; - } - - if (st->st_ipcomp.present) - { - spi = inbound ? st->st_ipcomp.our_spi : st->st_ipcomp.attrs.spi; - result &= hydra->kernel_interface->del_sa(hydra->kernel_interface, - host_src, host_dst, spi, IPPROTO_COMP, - 0 /* cpi */, mark) == SUCCESS; - } - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - - return result; -} - -/* - * get information about a given sa - */ -bool get_sa_info(struct state *st, bool inbound, u_int *bytes, time_t *use_time) -{ - connection_t *c = st->st_connection; - traffic_selector_t *ts_src = NULL, *ts_dst = NULL; - host_t *host_src = NULL, *host_dst = NULL; - const struct end *src, *dst; - ipsec_spi_t spi; - mark_t mark; - u_int64_t bytes_kernel = 0; - bool result = FALSE; - - *use_time = UNDEFINED_TIME; - - if (!st->st_esp.present) - { - goto failed; - } - - if (inbound) - { - src = &c->spd.that; - dst = &c->spd.this; - mark = c->spd.mark_in; - spi = st->st_esp.our_spi; - } - else - { - src = &c->spd.this; - dst = &c->spd.that; - mark = c->spd.mark_out; - spi = st->st_esp.attrs.spi; - } - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - switch(hydra->kernel_interface->query_sa(hydra->kernel_interface, host_src, - host_dst, spi, IPPROTO_ESP, - mark, &bytes_kernel)) - { - case FAILED: - goto failed; - case SUCCESS: - *bytes = bytes_kernel; - break; - case NOT_SUPPORTED: - default: - break; - } - - if (st->st_serialno == c->spd.eroute_owner) - { - u_int32_t time_kernel; - - ts_src = traffic_selector_from_subnet(&src->client, src->protocol); - ts_dst = traffic_selector_from_subnet(&dst->client, dst->protocol); - - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, inbound ? POLICY_IN : POLICY_OUT, - mark, &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = time_kernel; - - if (inbound && - st->st_esp.attrs.encapsulation == ENCAPSULATION_MODE_TUNNEL) - { - if (hydra->kernel_interface->query_policy(hydra->kernel_interface, - ts_src, ts_dst, POLICY_FWD, mark, - &time_kernel) != SUCCESS) - { - goto failed; - } - *use_time = max(*use_time, time_kernel); - } - } - - result = TRUE; - -failed: - DESTROY_IF(host_src); - DESTROY_IF(host_dst); - DESTROY_IF(ts_src); - DESTROY_IF(ts_dst); - return result; -} - -/** - * Handler for kernel events (called by thread-pool thread) - */ -kernel_listener_t *kernel_handler; - -/** - * Data for acquire events - */ -typedef struct { - /** Subnets */ - ip_subnet src, dst; - /** Transport protocol */ - int proto; -} acquire_data_t; - -/** - * Callback for acquire events (called by main thread) - */ -void handle_acquire(acquire_data_t *this) -{ - record_and_initiate_opportunistic(&this->src, &this->dst, this->proto, - "%acquire"); -} - -METHOD(kernel_listener_t, acquire, bool, - kernel_listener_t *this, u_int32_t reqid, - traffic_selector_t *src_ts, traffic_selector_t *dst_ts) -{ - if (src_ts && dst_ts) - { - acquire_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating acquire event for policy %R === %R " - "with reqid {%u}", src_ts, dst_ts, reqid)); - INIT(data, - .src = subnet_from_traffic_selector(src_ts), - .dst = subnet_from_traffic_selector(dst_ts), - .proto = src_ts->get_protocol(src_ts), - ); - pluto->events->queue(pluto->events, (void*)handle_acquire, data, free); - } - else - { - DBG(DBG_CONTROL, - DBG_log("ignoring acquire without traffic selectors for policy " - "with reqid {%u}", reqid)); - } - DESTROY_IF(src_ts); - DESTROY_IF(dst_ts); - return TRUE; -} - -/** - * Data for mapping events - */ -typedef struct { - /** reqid, spi of affected SA */ - u_int32_t reqid, spi; - /** new endpont */ - ip_address new_end; -} mapping_data_t; - -/** - * Callback for mapping events (called by main thread) - */ -void handle_mapping(mapping_data_t *this) -{ - process_nat_t_new_mapping(this->reqid, this->spi, &this->new_end); -} - - -METHOD(kernel_listener_t, mapping, bool, - kernel_listener_t *this, u_int32_t reqid, u_int32_t spi, host_t *remote) -{ - mapping_data_t *data; - DBG(DBG_CONTROL, - DBG_log("creating mapping event for SA with SPI %.8x and reqid {%u}", - spi, reqid)); - INIT(data, - .reqid = reqid, - .spi = spi, - .new_end = *(ip_address*)remote->get_sockaddr(remote), - ); - pluto->events->queue(pluto->events, (void*)handle_mapping, data, free); - return TRUE; -} - -void init_kernel(void) -{ - /* register SA types that we can negotiate */ - can_do_IPcomp = FALSE; /* until we get a response from the kernel */ - pfkey_register(); - - INIT(kernel_handler, - .acquire = _acquire, - .mapping = _mapping, - ); - hydra->kernel_interface->add_listener(hydra->kernel_interface, - kernel_handler); -} - -void kernel_finalize() -{ - hydra->kernel_interface->remove_listener(hydra->kernel_interface, - kernel_handler); - free(kernel_handler); -} - -/* Note: install_inbound_ipsec_sa is only used by the Responder. - * The Responder will subsequently use install_ipsec_sa for the outbound. - * The Initiator uses install_ipsec_sa to install both at once. - */ -bool install_inbound_ipsec_sa(struct state *st) -{ - connection_t *const c = st->st_connection; - - /* If our peer has a fixed-address client, check if we already - * have a route for that client that conflicts. We will take this - * as proof that that route and the connections using it are - * obsolete and should be eliminated. Interestingly, this is - * the only case in which we can tell that a connection is obsolete. - */ - passert(c->kind == CK_PERMANENT || c->kind == CK_INSTANCE); - if (c->spd.that.has_client) - { - for (;;) - { - struct spd_route *esr; - connection_t *o = route_owner(c, &esr, NULL, NULL); - - if (o == NULL) - { - break; /* nobody has a route */ - } - - /* note: we ignore the client addresses at this end */ - if (sameaddr(&o->spd.that.host_addr, &c->spd.that.host_addr) && - o->interface == c->interface) - { - break; /* existing route is compatible */ - } - - if (o->kind == CK_TEMPLATE && streq(o->name, c->name)) - { - break; /* ??? is this good enough?? */ - } - - loglog(RC_LOG_SERIOUS, "route to peer's client conflicts with \"%s\" %s; releasing old connection to free the route" - , o->name, ip_str(&o->spd.that.host_addr)); - release_connection(o, FALSE); - } - } - - DBG(DBG_CONTROL, DBG_log("install_inbound_ipsec_sa() checking if we can route")); - /* check that we will be able to route and eroute */ - switch (could_route(c)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SAs */ - return setup_half_ipsec_sa(st, TRUE); -} - -/* Install a route and then a prospective shunt eroute or an SA group eroute. - * Assumption: could_route gave a go-ahead. - * Any SA Group must have already been created. - * On failure, steps will be unwound. - */ -bool route_and_eroute(connection_t *c, struct spd_route *sr, struct state *st) -{ - struct spd_route *esr; - struct spd_route *rosr; - connection_t *ero /* who, if anyone, owns our eroute? */ - , *ro = route_owner(c, &rosr, &ero, &esr); - bool eroute_installed = FALSE - , firewall_notified = FALSE - , route_installed = FALSE; - - connection_t *ero_top; - - DBG(DBG_CONTROLMORE, - DBG_log("route_and_eroute with c: %s (next: %s) ero:%s esr:{%p} ro:%s rosr:{%p} and state: %lu" - , c->name - , (c->policy_next ? c->policy_next->name : "none") - , ero ? ero->name : "null" - , esr - , ro ? ro->name : "null" - , rosr - , st ? st->st_serialno : 0)); - - /* look along the chain of policies for one with the same name */ - ero_top = ero; - -#if 0 - /* XXX - mcr this made sense before, and likely will make sense - * again, so I'l leaving this to remind me what is up */ - if (ero!= NULL && ero->routing == RT_UNROUTED_KEYED) - ero = NULL; - - for (ero2 = ero; ero2 != NULL; ero2 = ero->policy_next) - if ((ero2->kind == CK_TEMPLATE || ero2->kind==CK_SECONDARY) - && streq(ero2->name, c->name)) - break; -#endif - - /* install the eroute */ - - if (ero != NULL) - { - /* We're replacing an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_REPLACE, "replace"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_REPLACE, "replace"); - } -#if 0 - /* XXX - MCR. I previously felt that this was a bogus check */ - if (ero != NULL && ero != c && esr != sr) - { - /* By elimination, we must be eclipsing ero. Check. */ - passert(ero->kind == CK_TEMPLATE && streq(ero->name, c->name)); - passert(LHAS(LELEM(RT_ROUTED_PROSPECTIVE) | LELEM(RT_ROUTED_ECLIPSED) - , esr->routing)); - passert(samesubnet(&esr->this.client, &sr->this.client) - && samesubnet(&esr->that.client, &sr->that.client)); - } -#endif - } - else - { - /* we're adding an eroute */ - - /* if no state provided, then install a shunt for later */ - if (st == NULL) - { - eroute_installed = shunt_eroute(c, sr, RT_ROUTED_PROSPECTIVE - , ERO_ADD, "add"); - } - else - { - eroute_installed = sag_eroute(st, sr, ERO_ADD, "add"); - } - } - - /* notify the firewall of a new tunnel */ - - if (eroute_installed) - { - /* do we have to notify the firewall? Yes, if we are installing - * a tunnel eroute and the firewall wasn't notified - * for a previous tunnel with the same clients. Any Previous - * tunnel would have to be for our connection, so the actual - * test is simple. - */ - firewall_notified = st == NULL /* not a tunnel eroute */ - || sr->eroute_owner != SOS_NOBODY /* already notified */ - || do_command(c, sr, st, "up"); /* go ahead and notify */ - } - - /* install the route */ - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: firewall_notified: %s" - , firewall_notified ? "true" : "false")); - if (!firewall_notified) - { - /* we're in trouble -- don't do routing */ - } - else if (ro == NULL) - { - /* a new route: no deletion required, but preparation is */ - (void) do_command(c, sr, st, "prepare"); /* just in case; ignore failure */ - route_installed = do_command(c, sr, st, "route"); - } - else if (routed(sr->routing) || routes_agree(ro, c)) - { - route_installed = TRUE; /* nothing to be done */ - } - else - { - /* Some other connection must own the route - * and the route must disagree. But since could_route - * must have allowed our stealing it, we'll do so. - * - * A feature of LINUX allows us to install the new route - * before deleting the old if the nexthops differ. - * This reduces the "window of vulnerability" when packets - * might flow in the clear. - */ - if (sameaddr(&sr->this.host_nexthop, &esr->this.host_nexthop)) - { - (void) do_command(ro, sr, st, "unroute"); - route_installed = do_command(c, sr, st, "route"); - } - else - { - route_installed = do_command(c, sr, st, "route"); - (void) do_command(ro, sr, st, "unroute"); - } - - /* record unrouting */ - if (route_installed) - { - do { - passert(!erouted(rosr->routing)); - rosr->routing = RT_UNROUTED; - - /* no need to keep old value */ - ro = route_owner(c, &rosr, NULL, NULL); - } while (ro != NULL); - } - } - - /* all done -- clean up */ - if (route_installed) - { - /* Success! */ - - if (ero != NULL && ero != c) - { - /* check if ero is an ancestor of c. */ - connection_t *ero2; - - for (ero2 = c; ero2 != NULL && ero2 != c; ero2 = ero2->policy_next) - ; - - if (ero2 == NULL) - { - /* By elimination, we must be eclipsing ero. Checked above. */ - if (ero->spd.routing != RT_ROUTED_ECLIPSED) - { - ero->spd.routing = RT_ROUTED_ECLIPSED; - eclipse_count++; - } - } - } - - if (st == NULL) - { - passert(sr->eroute_owner == SOS_NOBODY); - sr->routing = RT_ROUTED_PROSPECTIVE; - } - else - { - char cib[CONN_INST_BUF]; - sr->routing = RT_ROUTED_TUNNEL; - - DBG(DBG_CONTROL, - DBG_log("route_and_eroute: instance \"%s\"%s, setting eroute_owner {spd=%p,sr=%p} to #%ld (was #%ld) (newest_ipsec_sa=#%ld)" - , st->st_connection->name - , (fmt_conn_instance(st->st_connection, cib), cib) - , &st->st_connection->spd, sr - , st->st_serialno - , sr->eroute_owner - , st->st_connection->newest_ipsec_sa)); - sr->eroute_owner = st->st_serialno; - } - - return TRUE; - } - else - { - /* Failure! Unwind our work. */ - if (firewall_notified && sr->eroute_owner == SOS_NOBODY) - (void) do_command(c, sr, st, "down"); - - if (eroute_installed) - { - /* Restore original eroute, if we can. - * Since there is nothing much to be done if the restoration - * fails, ignore success or failure. - */ - if (ero != NULL) - { - /* restore ero's former glory */ - if (esr->eroute_owner == SOS_NOBODY) - { - /* note: normal or eclipse case */ - (void) shunt_eroute(ero, esr - , esr->routing, ERO_REPLACE, "restore"); - } - else - { - /* Try to find state that owned eroute. - * Don't do anything if it cannot be found. - * This case isn't likely since we don't run - * the updown script when replacing a SA group - * with its successor (for the same conn). - */ - struct state *ost = state_with_serialno(esr->eroute_owner); - - if (ost != NULL) - (void) sag_eroute(ost, esr, ERO_REPLACE, "restore"); - } - } - else - { - /* there was no previous eroute: delete whatever we installed */ - if (st == NULL) - { - (void) shunt_eroute(c, sr, sr->routing, ERO_DELETE, "delete"); - } - else - { - (void) sag_eroute(st, sr, ERO_DELETE, "delete"); - } - } - } - - return FALSE; - } -} - -bool install_ipsec_sa(struct state *st, bool inbound_also) -{ - struct spd_route *sr; - - DBG(DBG_CONTROL, DBG_log("install_ipsec_sa() for #%ld: %s" - , st->st_serialno - , inbound_also? - "inbound and outbound" : "outbound only")); - - switch (could_route(st->st_connection)) - { - case route_easy: - case route_nearconflict: - break; - default: - return FALSE; - } - - /* (attempt to) actually set up the SA group */ - if ((inbound_also && !setup_half_ipsec_sa(st, TRUE)) || - !setup_half_ipsec_sa(st, FALSE)) - { - return FALSE; - } - - for (sr = &st->st_connection->spd; sr != NULL; sr = sr->next) - { - DBG(DBG_CONTROL, DBG_log("sr for #%ld: %s" - , st->st_serialno - , enum_name(&routing_story, sr->routing))); - - /* - * if the eroute owner is not us, then make it us. - * See test co-terminal-02, pluto-rekey-01, pluto-unit-02/oppo-twice - */ - pexpect(sr->eroute_owner == SOS_NOBODY - || sr->routing >= RT_ROUTED_TUNNEL); - - if (sr->eroute_owner != st->st_serialno - && sr->routing != RT_UNROUTED_KEYED) - { - if (!route_and_eroute(st->st_connection, sr, st)) - { - delete_ipsec_sa(st, FALSE); - /* XXX go and unroute any SRs that were successfully - * routed already. - */ - return FALSE; - } - } - } - - return TRUE; -} - -/* delete an IPSEC SA. - * we may not succeed, but we bull ahead anyway because - * we cannot do anything better by recognizing failure - */ -void delete_ipsec_sa(struct state *st, bool inbound_only) -{ - if (!inbound_only) - { - /* If the state is the eroute owner, we must adjust - * the routing for the connection. - */ - connection_t *c = st->st_connection; - struct spd_route *sr; - - passert(st->st_connection); - - for (sr = &c->spd; sr; sr = sr->next) - { - if (sr->eroute_owner == st->st_serialno - && sr->routing == RT_ROUTED_TUNNEL) - { - sr->eroute_owner = SOS_NOBODY; - - /* Routing should become RT_ROUTED_FAILURE, - * but if POLICY_FAIL_NONE, then we just go - * right back to RT_ROUTED_PROSPECTIVE as if no - * failure happened. - */ - sr->routing = (c->policy & POLICY_FAIL_MASK) == POLICY_FAIL_NONE - ? RT_ROUTED_PROSPECTIVE : RT_ROUTED_FAILURE; - - (void) do_command(c, sr, st, "down"); - if ((c->policy & POLICY_DONT_REKEY) && c->kind == CK_INSTANCE) - { - /* in this special case, even if the connection - * is still alive (due to an ISAKMP SA), - * we get rid of routing. - * Even though there is still an eroute, the c->routing - * setting will convince unroute_connection to delete it. - * unroute_connection would be upset if c->routing == RT_ROUTED_TUNNEL - */ - unroute_connection(c); - } - else - { - (void) shunt_eroute(c, sr, sr->routing, ERO_REPLACE, "replace with shunt"); - } - } - } - (void) teardown_half_ipsec_sa(st, FALSE); - } - (void) teardown_half_ipsec_sa(st, TRUE); -} - -static bool update_nat_t_ipsec_esp_sa (struct state *st, bool inbound) -{ - connection_t *c = st->st_connection; - host_t *host_src, *host_dst, *new_src, *new_dst; - ipsec_spi_t spi = inbound ? st->st_esp.our_spi : st->st_esp.attrs.spi; - struct end *src = inbound ? &c->spd.that : &c->spd.this, - *dst = inbound ? &c->spd.this : &c->spd.that; - mark_t mark = inbound ? c->spd.mark_in : c->spd.mark_out; - bool result; - - host_src = host_create_from_sockaddr((sockaddr_t*)&src->host_addr); - host_dst = host_create_from_sockaddr((sockaddr_t*)&dst->host_addr); - - new_src = host_src->clone(host_src); - new_dst = host_dst->clone(host_dst); - new_src->set_port(new_src, src->host_port); - new_dst->set_port(new_dst, dst->host_port); - - result = hydra->kernel_interface->update_sa(hydra->kernel_interface, - spi, IPPROTO_ESP, 0 /* cpi */, host_src, host_dst, - new_src, new_dst, TRUE /* encap */, TRUE /* new_encap */, - mark) == SUCCESS; - - host_src->destroy(host_src); - host_dst->destroy(host_dst); - new_src->destroy(new_src); - new_dst->destroy(new_dst); - - return result; -} - -bool update_ipsec_sa (struct state *st) -{ - if (IS_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && ( - (!update_nat_t_ipsec_esp_sa (st, TRUE)) || - (!update_nat_t_ipsec_esp_sa (st, FALSE)))) - { - return FALSE; - } - } - else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (st->st_esp.present && !update_nat_t_ipsec_esp_sa (st, FALSE)) - { - return FALSE; - } - } - else - { - DBG_log("assert failed at %s:%d st_state=%d", __FILE__, __LINE__, st->st_state); - return FALSE; - } - return TRUE; -} - -/* Check if there was traffic on given SA during the last idle_max - * seconds. If TRUE, the SA was idle and DPD exchange should be performed. - * If FALSE, DPD is not necessary. We also return TRUE for errors, as they - * could mean that the SA is broken and needs to be replace anyway. - */ -bool was_eroute_idle(struct state *st, time_t idle_max, time_t *idle_time) -{ - time_t use_time; - u_int bytes; - int ret = TRUE; - - passert(st != NULL); - - if (get_sa_info(st, TRUE, &bytes, &use_time) && use_time != UNDEFINED_TIME) - { - *idle_time = time_monotonic(NULL) - use_time; - ret = *idle_time >= idle_max; - } - - return ret; -} diff --git a/src/pluto/kernel.h b/src/pluto/kernel.h deleted file mode 100644 index 1fa11c50e..000000000 --- a/src/pluto/kernel.h +++ /dev/null @@ -1,118 +0,0 @@ -/* declarations of routines that interface with the kernel's IPsec mechanism - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "connections.h" - -extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */ - -/* Declare eroute things early enough for uses. - * - * Flags are encoded above the low-order byte of verbs. - * "real" eroutes are only outbound. Inbound eroutes don't exist, - * but an addflow with an INBOUND flag allows IPIP tunnels to be - * limited to appropriate source and destination addresses. - */ - -#define ERO_MASK 0xFF -#define ERO_FLAG_SHIFT 8 - -#define ERO_DELETE SADB_X_DELFLOW -#define ERO_ADD SADB_X_ADDFLOW -#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT)) - -struct pfkey_proto_info { - int proto; - int encapsulation; - unsigned reqid; -}; -struct sadb_msg; - -struct kernel_sa { - const ip_address *src; - const ip_address *dst; - - const ip_subnet *src_client; - const ip_subnet *dst_client; - - ipsec_spi_t spi; - unsigned proto; - unsigned satype; - unsigned transport_proto; - unsigned replay_window; - unsigned reqid; - - unsigned authalg; - unsigned authkeylen; - char *authkey; - - unsigned encalg; - unsigned enckeylen; - char *enckey; - - unsigned compalg; - - int encapsulation; - - u_int16_t natt_sport, natt_dport; - u_int8_t transid, natt_type; - ip_address *natt_oa; - - const char *text_said; -}; - -/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group. - * Is there a PF_KEY equivalent? - */ -#ifndef EM_MAXRELSPIS -# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */ -#endif - -extern void record_and_initiate_opportunistic(const ip_subnet * - , const ip_subnet * - , int transport_proto - , const char *why); - -extern void init_kernel(void); -extern void kernel_finalize(void); - -extern bool trap_connection(struct connection *c); -extern void unroute_connection(struct connection *c); - -extern bool assign_hold(struct connection *c - , struct spd_route *sr - , int transport_proto - , const ip_address *src, const ip_address *dst); - -extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective); - - -struct state; /* forward declaration of tag */ -extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid - , int proto - , struct spd_route *sr - , bool tunnel_mode); -extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode); - -extern bool install_inbound_ipsec_sa(struct state *st); -extern bool install_ipsec_sa(struct state *st, bool inbound_also); -extern void delete_ipsec_sa(struct state *st, bool inbound_only); -extern bool route_and_eroute(struct connection *c - , struct spd_route *sr - , struct state *st); -extern bool was_eroute_idle(struct state *st, time_t idle_max - , time_t *idle_time); -extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes - , time_t *use_time); - -extern bool update_ipsec_sa(struct state *st); diff --git a/src/pluto/kernel_alg.c b/src/pluto/kernel_alg.c deleted file mode 100644 index b4b18fd80..000000000 --- a/src/pluto/kernel_alg.c +++ /dev/null @@ -1,663 +0,0 @@ -/* Kernel runtime algorithm handling interface - * Copyright (C) JuanJo Ciarlante - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "connections.h" -#include "state.h" -#include "packet.h" -#include "spdb.h" -#include "kernel.h" -#include "kernel_alg.h" -#include "alg_info.h" -#include "log.h" -#include "whack.h" -#include "db_ops.h" - -/* ALG storage */ -static struct sadb_alg esp_aalg[SADB_AALG_MAX+1]; -static struct sadb_alg esp_ealg[SADB_EALG_MAX+1]; -static int esp_ealg_num = 0; -static int esp_aalg_num = 0; - -#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo))) -#define ESP_EALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_EALG_MAX; algo >0 ; algo--) \ - if (ESP_EALG_PRESENT(algo)) -#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo))) -#define ESP_AALG_FOR_EACH_UPDOWN(algo) \ - for (algo=SADB_AALG_MAX; algo >0 ; algo--) \ - if (ESP_AALG_PRESENT(algo)) - -static struct sadb_alg* sadb_alg_ptr (int satype, int exttype, int alg_id, - int rw) -{ - struct sadb_alg *alg_p = NULL; - - switch (exttype) - { - case SADB_EXT_SUPPORTED_AUTH: - if (alg_id > SADB_AALG_MAX) - return NULL; - break; - case SADB_EXT_SUPPORTED_ENCRYPT: - if (alg_id > SADB_EALG_MAX) - return NULL; - break; - default: - return NULL; - } - - switch (satype) - { - case SADB_SATYPE_ESP: - alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - &esp_ealg[alg_id] : &esp_aalg[alg_id]; - /* get for write: increment elem count */ - if (rw) - { - (exttype == SADB_EXT_SUPPORTED_ENCRYPT)? - esp_ealg_num++ : esp_aalg_num++; - } - break; - case SADB_SATYPE_AH: - default: - return NULL; - } - - return alg_p; -} - -const struct sadb_alg* kernel_alg_sadb_alg_get(int satype, int exttype, - int alg_id) -{ - return sadb_alg_ptr(satype, exttype, alg_id, 0); -} - -/* - * Forget previous registration - */ -static void kernel_alg_init(void) -{ - DBG(DBG_KERNEL, - DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)", - &esp_aalg, (int)sizeof (esp_aalg), - &esp_ealg, (int)sizeof (esp_ealg)) - ) - memset (&esp_aalg, 0, sizeof (esp_aalg)); - memset (&esp_ealg, 0, sizeof (esp_ealg)); - esp_ealg_num=esp_aalg_num = 0; -} - -static int kernel_alg_add(int satype, int exttype, - const struct sadb_alg *sadb_alg) -{ - struct sadb_alg *alg_p = NULL; - int alg_id = sadb_alg->sadb_alg_id; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1))) - return -1; - - /* This logic "mimics" KLIPS: first algo implementation will be used */ - if (alg_p->sadb_alg_id) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_add(): discarding already setup " - "satype=%d, exttype=%d, alg_id=%d", - satype, exttype, sadb_alg->sadb_alg_id) - ) - return 0; - } - *alg_p = *sadb_alg; - return 1; -} - -bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - struct sadb_alg *alg_p = NULL; - - /* - * test #1: encrypt algo must be present - */ - int ret = ESP_EALG_PRESENT(alg_id); - if (!ret) goto out; - - alg_p = &esp_ealg[alg_id]; - - /* - * test #2: if key_len specified, it must be in range - */ - if (key_len - && (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits)) - { - plog("kernel_alg_db_add() key_len not in range: alg_id=%d, " - "key_len=%d, alg_minbits=%d, alg_maxbits=%d" - , alg_id, key_len - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits); - ret = FALSE; - } - -out: - if (ret) - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): " - "alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d, ret=%d" - , alg_id, key_len - , alg_p->sadb_alg_id - , alg_p->sadb_alg_ivlen - , alg_p->sadb_alg_minbits - , alg_p->sadb_alg_maxbits - , alg_p->sadb_alg_reserved - , ret); - ) - } - else - { - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len); - ) - } - return ret; -} - -/* - * ML: make F_STRICT logic consider enc,auth algorithms - */ -bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, - struct alg_info_esp *alg_info) -{ - int ealg_insecure; - - /* - * key_len passed comes from esp_attrs read from peer - * For many older algorithms (eg 3DES) this key_len is fixed - * and get passed as 0. - * ... then get default key_len - */ - if (key_len == 0) - key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE; - - /* - * simple test to toss low key_len, will accept it only - * if specified in "esp" string - */ - ealg_insecure = (key_len < 128) ; - - if (ealg_insecure - || (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT)) - { - int i; - struct esp_info *esp_info; - - if (alg_info) - { - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - if (esp_info->esp_ealg_id == ealg - && (esp_info->esp_ealg_keylen == 0 || key_len == 0 - || esp_info->esp_ealg_keylen == key_len) - && esp_info->esp_aalg_id == aalg) - { - if (ealg_insecure) - { - loglog(RC_LOG_SERIOUS - , "You should NOT use insecure ESP algorithms [%s (%d)]!" - , enum_name(&esp_transform_names, ealg), key_len); - } - return TRUE; - } - } - } - plog("IPSec Transform [%s (%d), %s] refused due to %s", - enum_name(&esp_transform_names, ealg), key_len, - enum_name(&auth_alg_names, aalg), - ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag"); - return FALSE; - } - return TRUE; -} - -/** - * Load kernel_alg arrays pluto's SADB_REGISTER user by pluto/kernel.c - */ -void kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen) -{ - /* Trick: one 'type-mangle-able' pointer to ease offset/assign */ - union { - const struct sadb_msg *msg; - const struct sadb_supported *supported; - const struct sadb_ext *ext; - const struct sadb_alg *alg; - const char *ch; - } sadb; - - int satype; - int msglen; - int i = 0; - - /* Initialize alg arrays */ - kernel_alg_init(); - satype = msg_buf->sadb_msg_satype; - sadb.msg = msg_buf; - msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN; - msglen -= sizeof(struct sadb_msg); - buflen -= sizeof(struct sadb_msg); - passert(buflen > 0); - - sadb.msg++; - - while (msglen) - { - int supp_exttype = sadb.supported->sadb_supported_exttype; - int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "sadb_msg_len=%d sadb_supported_len=%d" - , satype==SADB_SATYPE_ESP? "ESP" : "AH" - , msg_buf->sadb_msg_len, supp_len) - ) - sadb.supported++; - msglen -= supp_len; - buflen -= supp_len; - passert(buflen >= 0); - - for (supp_len -= sizeof(struct sadb_supported); - supp_len; - supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++) - { - kernel_alg_add(satype, supp_exttype, sadb.alg); - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: " - "alg[%d], exttype=%d, satype=%d, alg_id=%d, " - "alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, " - "res=%d" - , satype == SADB_SATYPE_ESP? "ESP" : "AH" - , i - , supp_exttype - , satype - , sadb.alg->sadb_alg_id - , sadb.alg->sadb_alg_ivlen - , sadb.alg->sadb_alg_minbits - , sadb.alg->sadb_alg_maxbits - , sadb.alg->sadb_alg_reserved) - ) - /* if AES_CBC is registered then also register AES_CCM and AES_GCM */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_ENCRYPT && - sadb.alg->sadb_alg_id == SADB_X_EALG_AESCBC) - { - struct sadb_alg alg = *sadb.alg; - int alg_id; - - for (alg_id = SADB_X_EALG_AES_CCM_ICV8; - alg_id <= SADB_X_EALG_AES_GCM_ICV16; alg_id++) - { - if (alg_id != ESP_UNASSIGNED_17) - { - alg.sadb_alg_id = alg_id; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - - /* also register AES_GMAC */ - alg.sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - /* if SHA2_256 is registered then also register SHA2_256_96 */ - if (satype == SADB_SATYPE_ESP && - supp_exttype == SADB_EXT_SUPPORTED_AUTH && - sadb.alg->sadb_alg_id == SADB_X_AALG_SHA2_256HMAC) - { - struct sadb_alg alg = *sadb.alg; - - alg.sadb_alg_id = SADB_X_AALG_SHA2_256_96HMAC; - kernel_alg_add(satype, supp_exttype, &alg); - } - } - } -} - -u_int kernel_alg_esp_enc_keylen(u_int alg_id) -{ - u_int keylen = 0; - - if (!ESP_EALG_PRESENT(alg_id)) - { - goto none; - } - keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE; - - switch (alg_id) - { - /* - * this is veryUgly[TM] - * Peer should have sent KEY_LENGTH attribute for ESP_AES - * but if not do force it to 128 instead of using sadb_alg_maxbits - * from kernel. - */ - case ESP_AES: - keylen = 128/BITS_PER_BYTE; - break; - } - -none: - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_enc_keylen(): alg_id=%d, keylen=%d", - alg_id, keylen) - ) - return keylen; -} - -struct sadb_alg* kernel_alg_esp_sadb_alg(u_int alg_id) -{ - struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id)) - ? &esp_ealg[alg_id] : NULL; - - DBG(DBG_KERNEL, - DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p" - , alg_id, sadb_alg) - ) - return sadb_alg; -} - -/** - * Print the name of a kernel algorithm - */ -static void print_alg(char *buf, int *len, enum_names *alg_names, int alg_type) -{ - char alg_name[BUF_LEN]; - int alg_name_len; - - alg_name_len = sprintf(alg_name, " %s", enum_name(alg_names, alg_type)); - if (*len + alg_name_len > CRYPTO_MAX_ALG_LINE) - { - whack_log(RC_COMMENT, "%s", buf); - *len = sprintf(buf, " "); - } - sprintf(buf + *len, "%s", alg_name); - *len += alg_name_len; -} - -void kernel_alg_list(void) -{ - char buf[BUF_LEN]; - int len; - u_int sadb_id; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of registered ESP Algorithms:"); - whack_log(RC_COMMENT, " "); - - len = sprintf(buf, " encryption:"); - for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++) - { - if (ESP_EALG_PRESENT(sadb_id)) - { - print_alg(buf, &len, &esp_transform_names, sadb_id); - } - } - whack_log(RC_COMMENT, "%s", buf); - - len = sprintf(buf, " integrity: "); - for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++) - { - if (ESP_AALG_PRESENT(sadb_id)) - { - u_int aaid = alg_info_esp_sadb2aa(sadb_id); - - print_alg(buf, &len, &auth_alg_names, aaid); - } - } - whack_log(RC_COMMENT, "%s", buf); -} - -void kernel_alg_show_connection(connection_t *c, const char *instance) -{ - struct state *st = state_with_serialno(c->newest_ipsec_sa); - - if (st && st->st_esp.present) - { - const char *aalg_name, *pfsgroup_name; - - aalg_name = (c->policy & POLICY_AUTHENTICATE) ? - enum_show(&ah_transform_names, st->st_ah.attrs.transid): - enum_show(&auth_alg_names, st->st_esp.attrs.auth); - - pfsgroup_name = (c->policy & POLICY_PFS) ? - (c->alg_info_esp && c->alg_info_esp->esp_pfsgroup) ? - enum_show(&oakley_group_names, - c->alg_info_esp->esp_pfsgroup) : - "" : ""; - - if (st->st_esp.attrs.key_len) - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s_%u/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - st->st_esp.attrs.key_len, aalg_name, pfsgroup_name); - } - else - { - whack_log(RC_COMMENT, "\"%s\"%s: ESP%s proposal: %s/%s/%s", - c->name, instance, - (st->st_ah.present) ? "/AH" : "", - enum_show(&esp_transform_names, st->st_esp.attrs.transid), - aalg_name, pfsgroup_name); - } - } -} - -bool kernel_alg_esp_auth_ok(u_int auth, - struct alg_info_esp *alg_info __attribute__((unused))) -{ - return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth)); -} - -u_int kernel_alg_esp_auth_keylen(u_int auth) -{ - u_int sadb_aalg = alg_info_esp_aa2sadb(auth); - - u_int a_keylen = (sadb_aalg) - ? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE - : 0; - - DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING, - DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): " - "a_keylen=%d", auth, sadb_aalg, a_keylen) - ) - return a_keylen; -} - -struct esp_info* kernel_alg_esp_info(int transid, int auth) -{ - int sadb_aalg, sadb_ealg; - static struct esp_info ei_buf; - - sadb_ealg = transid; - sadb_aalg = alg_info_esp_aa2sadb(auth); - - if (!ESP_EALG_PRESENT(sadb_ealg)) - goto none; - if (!ESP_AALG_PRESENT(sadb_aalg)) - goto none; - - memset(&ei_buf, 0, sizeof (ei_buf)); - ei_buf.transid = transid; - ei_buf.auth = auth; - - /* don't return "default" keylen because this value is used from - * setup_half_ipsec_sa() to "validate" keylen - * In effect, enckeylen will be used as "max" value - */ - ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE; - ei_buf.encryptalg = sadb_ealg; - ei_buf.authalg = sadb_aalg; - - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=%p, " - "enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d", - transid, auth, &ei_buf, - (int)ei_buf.enckeylen, (int)ei_buf.authkeylen, - ei_buf.encryptalg, ei_buf.authalg) - ) - return &ei_buf; - -none: - DBG(DBG_PARSING, - DBG_log("kernel_alg_esp_info():" - "transid=%d, auth=%d, ei=NULL", - transid, auth) - ) - return NULL; -} - -static void kernel_alg_policy_algorithms(struct esp_info *esp_info) -{ - u_int ealg_id = esp_info->esp_ealg_id; - - switch(ealg_id) - { - case 0: - case ESP_DES: - case ESP_3DES: - case ESP_NULL: - case ESP_CAST: - break; - default: - if (!esp_info->esp_ealg_keylen) - { - /* algos that need KEY_LENGTH - * - * Note: this is a very dirty hack ;-) - * Idea: Add a key_length_needed attribute to - * esp_ealg ?? - */ - esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits; - } - } -} - -static bool kernel_alg_db_add(struct db_context *db_ctx, - struct esp_info *esp_info, lset_t policy) -{ - u_int ealg_id, aalg_id; - - ealg_id = esp_info->esp_ealg_id; - - if (!ESP_EALG_PRESENT(ealg_id)) - { - DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id); - return FALSE; - } - - if (!(policy & POLICY_AUTHENTICATE) && /* skip ESP auth attrs for AH */ - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id); - - if (!ESP_AALG_PRESENT(aalg_id)) - { - DBG_log("kernel_alg_db_add() kernel auth aalg_id=%d not present", - aalg_id); - return FALSE; - } - } - - /* do algo policy */ - kernel_alg_policy_algorithms(esp_info); - - /* open new transformation */ - db_trans_add(db_ctx, ealg_id); - - /* add ESP auth attr if not AH or AEAD */ - if (!(policy & POLICY_AUTHENTICATE) && - esp_info->esp_aalg_id != AUTH_ALGORITHM_NONE) - { - db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id); - } - - /* add keylength if specified in esp= string */ - if (esp_info->esp_ealg_keylen) - { - db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen); - } - - return TRUE; -} - -/* - * Create proposal with runtime kernel algos, merging - * with passed proposal if not NULL - * - * for now this function does free() previous returned - * malloced pointer (this quirk allows easier spdb.c change) - */ -struct db_context* kernel_alg_db_new(struct alg_info_esp *alg_info, - lset_t policy) -{ - const struct esp_info *esp_info; - struct esp_info tmp_esp_info; - struct db_context *ctx_new = NULL; - u_int trans_cnt = esp_ealg_num * esp_aalg_num; - - if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */ - { - return NULL; - } - - /* pass aprox. number of transforms and attributes */ - ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); - - if (alg_info) - { - int i; - - ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) - { - tmp_esp_info = *esp_info; - kernel_alg_db_add(ctx_new, &tmp_esp_info, policy); - } - } - return ctx_new; -} - diff --git a/src/pluto/kernel_alg.h b/src/pluto/kernel_alg.h deleted file mode 100644 index 4c757db41..000000000 --- a/src/pluto/kernel_alg.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Kernel runtime algorithm handling interface definitions - * Author: JuanJo Ciarlante - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KERNEL_ALG_H -#define _KERNEL_ALG_H - -#include "alg_info.h" -#include "spdb.h" - -/* status info */ -extern void kernel_alg_show_status(void); -void kernel_alg_show_connection(struct connection *c, const char *instance); - -/* Registration messages from pluto */ -extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen); - -/* ESP interface */ -extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id); -extern u_int kernel_alg_esp_ivlen(u_int alg_id); -extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo); -extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info); -extern u_int kernel_alg_esp_enc_keylen(u_int alg_id); -extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo); -extern u_int kernel_alg_esp_auth_keylen(u_int auth); -extern void kernel_alg_list(void); - -/* get sadb_alg for passed args */ -extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id); - -extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy); -struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id); -#endif /* _KERNEL_ALG_H */ diff --git a/src/pluto/kernel_pfkey.c b/src/pluto/kernel_pfkey.c deleted file mode 100644 index 77fff2f9e..000000000 --- a/src/pluto/kernel_pfkey.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2003 Herbert Xu. - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 1997 Angelos D. Keromytis. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include "constants.h" -#include "kernel.h" -#include "kernel_pfkey.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "kernel_alg.h" - - -static int pfkeyfd = NULL_FD; - -typedef u_int32_t pfkey_seq_t; -static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */ - -static pid_t pid; - -#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */ - -static sparse_names pfkey_type_names = { - NE(SADB_RESERVED), - NE(SADB_GETSPI), - NE(SADB_UPDATE), - NE(SADB_ADD), - NE(SADB_DELETE), - NE(SADB_GET), - NE(SADB_ACQUIRE), - NE(SADB_REGISTER), - NE(SADB_EXPIRE), - NE(SADB_FLUSH), - NE(SADB_DUMP), - NE(SADB_X_PROMISC), - NE(SADB_X_PCHANGE), - NE(SADB_X_GRPSA), - NE(SADB_X_ADDFLOW), - NE(SADB_X_DELFLOW), - NE(SADB_X_DEBUG), - NE(SADB_X_NAT_T_NEW_MAPPING), - NE(SADB_MAX), - { 0, sparse_end } -}; - -#undef NE - -typedef union { - unsigned char bytes[PFKEYv2_MAX_MSGSIZE]; - struct sadb_msg msg; - } pfkey_buf; - -static bool -pfkey_input_ready(void) -{ - int ndes; - fd_set readfds; - struct timeval tm = { .tv_sec = 0 }; /* don't wait, polling */ - - FD_ZERO(&readfds); /* we only care about pfkeyfd */ - FD_SET(pfkeyfd, &readfds); - - do { - ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm); - } while (ndes == -1 && errno == EINTR); - - if (ndes < 0) - { - log_errno((e, "select() failed in pfkey_get()")); - return FALSE; - } - else if (ndes == 0) - { - return FALSE; /* nothing to read */ - } - passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds)); - return TRUE; -} - -/* get a PF_KEY message from kernel. - * Returns TRUE if message found, FALSE if no message pending, - * and aborts or keeps trying when an error is encountered. - * The only validation of the message is that the message length - * received matches that in the message header, and that the message - * is for this process. - */ -static bool -pfkey_get(pfkey_buf *buf) -{ - for (;;) - { - /* len must be less than PFKEYv2_MAX_MSGSIZE, - * so it should fit in an int. We use this fact when printing it. - */ - ssize_t len; - - if (!pfkey_input_ready()) - { - return FALSE; - } - - len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes)); - - if (len < 0) - { - if (errno == EAGAIN) - { - return FALSE; - } - log_errno((e, "read() failed in pfkey_get()")); - return FALSE; - } - else if ((size_t)len < sizeof(buf->msg)) - { - plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring", - (int)len); - } - else if ((size_t)len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN) - { - plog("pfkey_get read PF_KEY message with length %d that doesn't" - " equal sadb_msg_len %u * %u; ignoring message", (int)len, - (unsigned)buf->msg.sadb_msg_len, (unsigned)IPSEC_PFKEYv2_ALIGN); - } - else if (buf->msg.sadb_msg_pid != (unsigned)pid) - { - /* not for us: ignore */ - DBG(DBG_KERNEL, - DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process" - " %u", sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq, buf->msg.sadb_msg_pid)); - } - else - { - DBG(DBG_KERNEL, - DBG_log("pfkey_get: %s message %u", - sparse_val_show(pfkey_type_names, - buf->msg.sadb_msg_type), - buf->msg.sadb_msg_seq)); - return TRUE; - } - } -} - -/* get a response to a specific message */ -static bool -pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq) -{ - while (pfkey_get(buf)) - { - if (buf->msg.sadb_msg_seq == seq) - { - return TRUE; - } - } - return FALSE; -} - -static bool -pfkey_build(int error, const char *description, const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d", description, - text_said, error); - pfkey_extensions_free(extensions); - return FALSE; - } - return TRUE; -} - -/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */ -static bool -pfkey_msg_start(u_int8_t msg_type, u_int8_t satype, const char *description, - const char *text_said, - struct sadb_ext *extensions[SADB_EXT_MAX + 1]) -{ - pfkey_extensions_init(extensions); - return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type, satype, 0, - ++pfkey_seq, pid), - description, text_said, extensions); -} - -/* Finish (building, sending, accepting response for) PF_KEY message. - * If response isn't NULL, the response from the kernel will be - * placed there (and its errno field will not be examined). - * Returns TRUE iff all appears well. - */ -static bool -finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1], - const char *description, const char *text_said, - pfkey_buf *response) -{ - struct sadb_msg *pfkey_msg; - bool success = TRUE; - int error; - - error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); - - if (error != 0) - { - loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d", - description, text_said, error); - success = FALSE; - } - else - { - size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; - - DBG(DBG_KERNEL, - DBG_log("finish_pfkey_msg: %s message %u for %s %s", - sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type), - pfkey_msg->sadb_msg_seq, description, text_said); - DBG_dump(NULL, (void *) pfkey_msg, len)); - - ssize_t r = write(pfkeyfd, pfkey_msg, len); - - if (r != (ssize_t)len) - { - if (r < 0) - { - log_errno((e, "pfkey write() of %s message %u for %s %s" - " failed", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said)); - } - else - { - loglog(RC_LOG_SERIOUS, "ERROR: pfkey write() of %s message" - " %u for %s %s truncated: %ld instead of %ld", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_seq, - description, text_said, (long)r, (long)len); - } - success = FALSE; - - /* if we were compiled with debugging, but we haven't already - * dumped the command, do so. - */ -#ifdef DEBUG - if ((cur_debugging & DBG_KERNEL) == 0) - DBG_dump(NULL, (void *) pfkey_msg, len); -#endif - } - else - { - /* Check response from kernel. - * It ought to be an echo, perhaps with additional info. - * If the caller wants it, response will point to space. - */ - pfkey_buf b; - pfkey_buf *bp = response != NULL? response : &b; - - if (!pfkey_get_response(bp, - ((struct sadb_msg *)extensions[0])->sadb_msg_seq)) - { - loglog(RC_LOG_SERIOUS, "ERROR: no response to our PF_KEY %s" - " message for %s %s", sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said); - success = FALSE; - } - else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) - { - loglog(RC_LOG_SERIOUS, "ERROR: response to our PF_KEY %s" - " message for %s %s was of wrong type (%s)", - sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type), - description, text_said, sparse_val_show(pfkey_type_names, - bp->msg.sadb_msg_type)); - success = FALSE; - } - else if (response == NULL && bp->msg.sadb_msg_errno != 0) - { - /* Kernel is signalling a problem */ - loglog(RC_LOG_SERIOUS, "ERROR: PF_KEY %s response for %s %s" - " included errno %u: %s", - sparse_val_show(pfkey_type_names, - pfkey_msg->sadb_msg_type), description, text_said, - (unsigned) bp->msg.sadb_msg_errno, - strerror(bp->msg.sadb_msg_errno)); - success = FALSE; - } - } - } - pfkey_extensions_free(extensions); - pfkey_msg_free(&pfkey_msg); - return success; -} - -/* Process a SADB_REGISTER message from the kernel. - * This will be a response to one of ours, but it may be asynchronous - * (if kernel modules are loaded and unloaded). - * Some sanity checking has already been performed. - */ -static void -pfkey_register_response(const struct sadb_msg *msg) -{ - /* Find out what the kernel can support. - */ - switch (msg->sadb_msg_satype) - { - case SADB_SATYPE_ESP: -#ifndef NO_KERNEL_ALG - kernel_alg_register_pfkey(msg, sizeof (pfkey_buf)); -#endif - break; - case SADB_X_SATYPE_IPCOMP: - /* ??? There ought to be an extension to list the - * supported algorithms, but RFC 2367 doesn't - * list one for IPcomp. - */ - can_do_IPcomp = TRUE; - break; - default: - break; - } -} - -/** register SA types that can be negotiated */ -static void -pfkey_register_proto(unsigned satype, const char *satypename) -{ - struct sadb_ext *extensions[SADB_EXT_MAX + 1]; - pfkey_buf pfb; - - if (!(pfkey_msg_start(SADB_REGISTER, satype, satypename, NULL, extensions) - && finish_pfkey_msg(extensions, satypename, "", &pfb))) - { - /* ??? should this be loglog */ - plog("no kernel support for %s", satypename); - } - else - { - pfkey_register_response(&pfb.msg); - DBG(DBG_KERNEL, - DBG_log("%s registered with kernel.", satypename)); - } -} - -void -pfkey_register(void) -{ - pid = getpid(); - - pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); - if (pfkeyfd == -1) - { - exit_log_errno((e, "socket() in init_pfkeyfd()")); - } - - pfkey_register_proto(SADB_SATYPE_AH, "AH"); - pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); - pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); - - close(pfkeyfd); -} diff --git a/src/pluto/kernel_pfkey.h b/src/pluto/kernel_pfkey.h deleted file mode 100644 index b50ad6c37..000000000 --- a/src/pluto/kernel_pfkey.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * Register our capabilities via PF_KEY, also learn the kernel's capabilities, - * i.e. the supported algorithms. - */ -void pfkey_register(); diff --git a/src/pluto/keys.c b/src/pluto/keys.c deleted file mode 100644 index c5adbfd11..000000000 --- a/src/pluto/keys.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include - -#ifdef HAVE_GLOB_H -#include -#ifndef GLOB_ABORTED -# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */ -#endif -#endif - -#include - -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "x509.h" -#include "certs.h" -#include "smartcard.h" -#include "connections.h" -#include "state.h" -#include "lex.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "timer.h" -#include "fetch.h" - -const char *shared_secrets_file = SHARED_SECRETS_FILE; - - -typedef enum secret_kind_t secret_kind_t; - -enum secret_kind_t { - SECRET_PSK, - SECRET_PUBKEY, - SECRET_XAUTH, - SECRET_PIN -}; - -typedef struct secret_t secret_t; - -struct secret_t { - linked_list_t *ids; - secret_kind_t kind; - union { - chunk_t preshared_secret; - private_key_t *private_key; - smartcard_t *smartcard; - } u; - secret_t *next; -}; - -/* - * free a public key struct - */ -static void free_public_key(pubkey_t *pk) -{ - DESTROY_IF(pk->id); - DESTROY_IF(pk->public_key); - DESTROY_IF(pk->issuer); - free(pk->serial.ptr); - free(pk); -} - -secret_t *secrets = NULL; - -/** - * Find the secret associated with the combination of me and the peer. - */ -const secret_t* match_secret(identification_t *my_id, identification_t *his_id, - secret_kind_t kind) -{ - enum { /* bits */ - match_default = 0x01, - match_him = 0x02, - match_me = 0x04 - }; - - unsigned int best_match = 0; - secret_t *s, *best = NULL; - - for (s = secrets; s != NULL; s = s->next) - { - unsigned int match = 0; - - if (s->kind != kind) - { - continue; - } - - if (s->ids->get_count(s->ids) == 0) - { - /* a default (signified by lack of ids): - * accept if no more specific match found - */ - match = match_default; - } - else - { - /* check if both ends match ids */ - enumerator_t *enumerator; - identification_t *id; - - enumerator = s->ids->create_enumerator(s->ids); - while (enumerator->enumerate(enumerator, &id)) - { - if (my_id->equals(my_id, id)) - { - match |= match_me; - } - if (his_id->equals(his_id, id)) - { - match |= match_him; - } - } - enumerator->destroy(enumerator); - - /* If our end matched the only id in the list, - * default to matching any peer. - * A more specific match will trump this. - */ - if (match == match_me && s->ids->get_count(s->ids) == 1) - { - match |= match_default; - } - } - - switch (match) - { - case match_me: - /* if this is an asymmetric (eg. public key) system, - * allow this-side-only match to count, even if - * there are other ids in the list. - */ - if (kind != SECRET_PUBKEY) - { - break; - } - /* FALLTHROUGH */ - case match_default: /* default all */ - case match_me | match_default: /* default peer */ - case match_me | match_him: /* explicit */ - if (match == best_match) - { - /* two good matches are equally good: do they agree? */ - bool same = FALSE; - - switch (kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - same = chunk_equals(s->u.preshared_secret, - best->u.preshared_secret); - break; - case SECRET_PUBKEY: - same = s->u.private_key->equals(s->u.private_key, - best->u.private_key); - break; - default: - bad_case(kind); - } - if (!same) - { - loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with " - "distinct secrets match endpoints: first secret used"); - best = s; /* list is backwards: take latest in list */ - } - } - else if (match > best_match) - { - /* this is the best match so far */ - best_match = match; - best = s; - } - } - } - return best; -} - -/** - * Retrieves an XAUTH secret primarily based on the user ID and - * secondarily based on the server ID - */ -bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret) -{ - const secret_t *s; - - s = match_secret(user, server, SECRET_XAUTH); - if (s) - { - *secret = chunk_clone(s->u.preshared_secret); - return TRUE; - } - else - { - *secret = chunk_empty; - return FALSE; - } -} - -/** - * We match the ID (if none, the IP address). Failure is indicated by a NULL. - */ -static const secret_t* get_secret(const connection_t *c, secret_kind_t kind) -{ - identification_t *my_id, *his_id; - const secret_t *best; - - my_id = c->spd.this.id; - - if (his_id_was_instantiated(c)) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else if (kind == SECRET_PSK && (c->policy & (POLICY_PSK | POLICY_XAUTH_PSK)) && - ((c->kind == CK_TEMPLATE && - c->spd.that.id->get_type(c->spd.that.id) == ID_ANY) || - (c->kind == CK_INSTANCE && id_is_ipaddr(c->spd.that.id)))) - { - /* roadwarrior: replace him with 0.0.0.0 */ - his_id = identification_create_from_string("%any"); - } - else - { - his_id = c->spd.that.id->clone(c->spd.that.id); - } - - best = match_secret(my_id, his_id, kind); - - his_id->destroy(his_id); - return best; -} - -/* find the appropriate preshared key (see get_secret). - * Failure is indicated by a NULL pointer. - * Note: the result is not to be freed by the caller. - */ -const chunk_t* get_preshared_secret(const connection_t *c) -{ - const secret_t *s = get_secret(c, SECRET_PSK); - - DBG(DBG_PRIVATE, - if (s == NULL) - DBG_log("no Preshared Key Found"); - else - DBG_dump_chunk("Preshared Key", s->u.preshared_secret); - ) - return s == NULL? NULL : &s->u.preshared_secret; -} - -/* check the existence of a private key matching a public key contained - * in an X.509 or OpenPGP certificate - */ -bool has_private_key(cert_t *cert) -{ - secret_t *s; - bool has_key = FALSE; - public_key_t *pub_key = cert->cert->get_public_key(cert->cert); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - has_key = TRUE; - break; - } - } - pub_key->destroy(pub_key); - return has_key; -} - -/* - * get the matching private key belonging to a given X.509 certificate - */ -private_key_t* get_x509_private_key(const cert_t *cert) -{ - public_key_t *public_key = cert->cert->get_public_key(cert->cert); - private_key_t *private_key = NULL; - secret_t *s; - - for (s = secrets; s != NULL; s = s->next) - { - - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, public_key)) - { - private_key = s->u.private_key; - break; - } - } - public_key->destroy(public_key); - return private_key; -} - -/* find the appropriate private key (see get_secret). - * Failure is indicated by a NULL pointer. - */ -private_key_t* get_private_key(const connection_t *c) -{ - const secret_t *s, *best = NULL; - - /* is a certificate assigned to this connection? */ - if (c->spd.this.cert) - { - certificate_t *certificate; - public_key_t *pub_key; - - certificate = c->spd.this.cert->cert; - pub_key = certificate->get_public_key(certificate); - - for (s = secrets; s != NULL; s = s->next) - { - if (s->kind == SECRET_PUBKEY && - s->u.private_key->belongs_to(s->u.private_key, pub_key)) - { - best = s; - break; /* found the private key - no sense in searching further */ - } - } - pub_key->destroy(pub_key); - } - else - { - best = get_secret(c, SECRET_PUBKEY); - } - return best ? best->u.private_key : NULL; -} - -/* digest a secrets file - * - * The file is a sequence of records. A record is a maximal sequence of - * tokens such that the first, and only the first, is in the first column - * of a line. - * - * Tokens are generally separated by whitespace and are key words, ids, - * strings, or data suitable for ttodata(3). As a nod to convention, - * a trailing ":" on what would otherwise be a token is taken as a - * separate token. If preceded by whitespace, a "#" is taken as starting - * a comment: it and the rest of the line are ignored. - * - * One kind of record is an include directive. It starts with "include". - * The filename is the only other token in the record. - * If the filename does not start with /, it is taken to - * be relative to the directory containing the current file. - * - * The other kind of record describes a key. It starts with a - * sequence of ids and ends with key information. Each id - * is an IP address, a Fully Qualified Domain Name (which will immediately - * be resolved), or @FQDN which will be left as a name. - * - * The key part can be in several forms. - * - * The old form of the key is still supported: a simple - * quoted strings (with no escapes) is taken as a preshred key. - * - * The new form starts the key part with a ":". - * - * For Preshared Key, use the "PSK" keyword, and follow it by a string - * or a data token suitable for ttodata(3). - * - * For RSA Private Key, use the "RSA" keyword, followed by a - * brace-enclosed list of key field keywords and data values. - * The data values are large integers to be decoded by ttodata(3). - * The fields are a subset of those used by BIND 8.2 and have the - * same names. - */ - -/* parse PSK from file */ -static err_t process_psk_secret(chunk_t *psk) -{ - err_t ugh = NULL; - - if (*tok == '"' || *tok == '\'') - { - chunk_t secret = { tok + 1, flp->cur - tok -2 }; - - *psk = chunk_clone(secret); - (void) shift(); - } - else - { - char buf[BUF_LEN]; /* limit on size of binary representation of key */ - size_t sz; - - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz - , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh != NULL) - { - /* ttodata didn't like PSK data */ - ugh = builddiag("PSK data malformed (%s): %s", ugh, tok); - } - else - { - chunk_t secret = { buf, sz }; - *psk = chunk_clone(secret); - (void) shift(); - } - } - return ugh; -} - -typedef enum rsa_private_key_part_t rsa_private_key_part_t; - -enum rsa_private_key_part_t { - RSA_PART_MODULUS = 0, - RSA_PART_PUBLIC_EXPONENT = 1, - RSA_PART_PRIVATE_EXPONENT = 2, - RSA_PART_PRIME1 = 3, - RSA_PART_PRIME2 = 4, - RSA_PART_EXPONENT1 = 5, - RSA_PART_EXPONENT2 = 6, - RSA_PART_COEFFICIENT = 7 -}; - -const char *rsa_private_key_part_names[] = { - "Modulus", - "PublicExponent", - "PrivateExponent", - "Prime1", - "Prime2", - "Exponent1", - "Exponent2", - "Coefficient" -}; - -/** - * Parse fields of an RSA private key in BIND 8.2's representation - * consistiong of a braced list of keyword and value pairs in required order. - */ -static err_t process_rsa_secret(private_key_t **key) -{ - chunk_t rsa_chunk[countof(rsa_private_key_part_names)]; - u_char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ - rsa_private_key_part_t part, p; - size_t sz; - err_t ugh; - - for (part = RSA_PART_MODULUS; part <= RSA_PART_COEFFICIENT; part++) - { - const char *keyword = rsa_private_key_part_names[part]; - - if (!shift()) - { - ugh = "premature end of RSA key"; - goto end; - } - if (!tokeqword(keyword)) - { - ugh = builddiag("%s keyword not found where expected in RSA key" - , keyword); - goto end; - } - if (!(shift() && (!tokeq(":") || shift()))) /* ignore optional ":" */ - { - ugh = "premature end of RSA key"; - goto end; - } - ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz, - diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); - if (ugh) - { - ugh = builddiag("RSA data malformed (%s): %s", ugh, tok); - goto end; - } - rsa_chunk[part] = chunk_create(buf, sz); - rsa_chunk[part] = chunk_clone(rsa_chunk[part]); - } - - /* We require an (indented) '}' and the end of the record. - * We break down the test so that the diagnostic will be more helpful. - * Some people don't seem to wish to indent the brace! - */ - if (!shift() || !tokeq("}")) - { - ugh = "malformed end of RSA private key -- indented '}' required"; - goto end; - } - if (shift()) - { - ugh = "malformed end of RSA private key -- unexpected token after '}'"; - goto end; - } - - *key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, - BUILD_RSA_MODULUS, rsa_chunk[RSA_PART_MODULUS], - BUILD_RSA_PUB_EXP, rsa_chunk[RSA_PART_PUBLIC_EXPONENT], - BUILD_RSA_PRIV_EXP, rsa_chunk[RSA_PART_PRIVATE_EXPONENT], - BUILD_RSA_PRIME1, rsa_chunk[RSA_PART_PRIME1], - BUILD_RSA_PRIME2, rsa_chunk[RSA_PART_PRIME2], - BUILD_RSA_EXP1, rsa_chunk[RSA_PART_EXPONENT1], - BUILD_RSA_EXP2, rsa_chunk[RSA_PART_EXPONENT2], - BUILD_RSA_COEFF, rsa_chunk[RSA_PART_COEFFICIENT], - BUILD_END); - - if (*key == NULL) - { - ugh = "parsing of RSA private key failed"; - } - -end: - /* clean up and return */ - for (p = RSA_PART_MODULUS ; p < part; p++) - { - chunk_clear(&rsa_chunk[p]); - } - return ugh; -} - -/* struct used to prompt for a secret passphrase - * from a console with file descriptor fd - */ -typedef struct { - char secret[PROMPT_PASS_LEN+1]; - bool prompt; - int fd; - int try; -} prompt_pass_t; - -/** - * Passphrase callback to read from whack fd - */ -static shared_key_t* whack_pass_cb(prompt_pass_t *pass, shared_key_type_t type, - identification_t *me, identification_t *other, - id_match_t *match_me, id_match_t *match_other) -{ - int n; - - if (type != SHARED_ANY && type != SHARED_PRIVATE_KEY_PASS) - { - return NULL; - } - - if (pass->try > MAX_PROMPT_PASS_TRIALS) - { - whack_log(RC_LOG_SERIOUS, "invalid passphrase, too many trials"); - return NULL; - } - if (pass->try == 1) - { - whack_log(RC_ENTERSECRET, "need passphrase for 'private key'"); - } - else - { - whack_log(RC_ENTERSECRET, "invalid passphrase, please try again"); - } - pass->try++; - - n = read(pass->fd, pass->secret, PROMPT_PASS_LEN); - if (n == -1) - { - whack_log(RC_LOG_SERIOUS, "read(whackfd) failed"); - return NULL; - } - pass->secret[n-1] = '\0'; - - if (strlen(pass->secret) == 0) - { - whack_log(RC_LOG_SERIOUS, "no passphrase entered, aborted"); - return NULL; - } - if (match_me) - { - *match_me = ID_MATCH_PERFECT; - } - if (match_other) - { - *match_other = ID_MATCH_NONE; - } - return shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); -} - -/** - * Loads a PKCS#1 or PGP private key file - */ -static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, - key_type_t type) -{ - private_key_t *key = NULL; - char *path; - - path = concatenate_paths(PRIVATE_KEY_PATH, filename); - if (pass && pass->prompt && pass->fd != NULL_FD) - { /* use passphrase callback */ - callback_cred_t *cb; - - cb = callback_cred_create_shared((void*)whack_pass_cb, pass); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); - - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &cb->set); - cb->destroy(cb); - if (key) - { - whack_log(RC_SUCCESS, "valid passphrase"); - } - } - else if (pass) - { /* use a given passphrase */ - mem_cred_t *mem; - shared_key_t *shared; - - mem = mem_cred_create(); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); - shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, - chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); - mem->add_shared(mem, shared, NULL); - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - lib->credmgr->remove_local_set(lib->credmgr, &mem->set); - mem->destroy(mem); - } - else - { /* no passphrase */ - key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, - BUILD_FROM_FILE, path, BUILD_END); - - } - if (key) - { - plog(" loaded private key from '%s'", filename); - } - else - { - plog(" syntax error in private key file"); - } - return key; -} - -/** - * process a key file protected with optional passphrase which can either be - * read from ipsec.secrets or prompted for by using whack - */ -static err_t process_keyfile(private_key_t **key, key_type_t type, int whackfd) -{ - char filename[BUF_LEN]; - prompt_pass_t pass; - - memset(filename,'\0', BUF_LEN); - memset(pass.secret,'\0', sizeof(pass.secret)); - pass.prompt = FALSE; - pass.fd = whackfd; - pass.try = 1; - - /* we expect the filename of a PKCS#1 private key file */ - - if (*tok == '"' || *tok == '\'') /* quoted filename */ - memcpy(filename, tok+1, flp->cur - tok - 2); - else - memcpy(filename, tok, flp->cur - tok); - - if (shift()) - { - /* we expect an appended passphrase or passphrase prompt*/ - if (tokeqword("%prompt")) - { - if (pass.fd == NULL_FD) - { - return "Private key file -- enter passphrase using 'ipsec secrets'"; - } - pass.prompt = TRUE; - } - else - { - char *passphrase = tok; - size_t len = flp->cur - passphrase; - - if (*tok == '"' || *tok == '\'') /* quoted passphrase */ - { - passphrase++; - len -= 2; - } - if (len > PROMPT_PASS_LEN) - { - return "Private key file -- passphrase exceeds 64 characters"; - } - memcpy(pass.secret, passphrase, len); - } - if (shift()) - { - return "Private key file -- unexpected token after passphrase"; - } - } - *key = load_private_key(filename, &pass, type); - - return *key ? NULL : "Private key file -- could not be loaded"; -} - -/** - * Process pin read from ipsec.secrets or prompted for it using whack - */ -static err_t process_pin(secret_t *s, int whackfd) -{ - smartcard_t *sc; - const char *pin_status = "no pin"; - - s->kind = SECRET_PIN; - - /* looking for the smartcard keyword */ - if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0) - return "PIN keyword must be followed by %smartcard:"; - - sc = scx_add(scx_parse_number_slot_id(tok + strlen(SCX_TOKEN))); - s->u.smartcard = sc; - scx_share(sc); - if (sc->pin.ptr != NULL) - { - scx_release_context(sc); - scx_free_pin(&sc->pin); - } - sc->valid = FALSE; - - if (!shift()) - return "PIN statement must be terminated either by , %pinpad or %prompt"; - - if (tokeqword("%prompt")) - { - shift(); - /* if whackfd exists, whack will be used to prompt for a pin */ - if (whackfd != NULL_FD) - pin_status = scx_get_pin(sc, whackfd) ? "valid pin" : "invalid pin"; - else - pin_status = "pin entry via prompt"; - } - else if (tokeqword("%pinpad")) - { - chunk_t empty_pin = { "", 0 }; - - shift(); - - /* pin will be entered via pin pad during verification */ - sc->pin = chunk_clone(empty_pin); - sc->pinpad = TRUE; - sc->valid = TRUE; - pin_status = "pin entry via pad"; - if (pkcs11_keep_state) - { - scx_verify_pin(sc); - } - } - else - { - /* we read the pin directly from ipsec.secrets */ - err_t ugh = process_psk_secret(&sc->pin); - if (ugh != NULL) - return ugh; - /* verify the pin */ - pin_status = scx_verify_pin(sc) ? "valid PIN" : "invalid PIN"; - } -#ifdef SMARTCARD - { - char buf[BUF_LEN]; - - if (sc->any_slot) - snprintf(buf, BUF_LEN, "any slot"); - else - snprintf(buf, BUF_LEN, "slot: %lu", sc->slot); - - plog(" %s for #%d (%s, id: %s)" - , pin_status, sc->number, scx_print_slot(sc, ""), sc->id); - } -#else - plog(" warning: SMARTCARD support is deactivated in pluto/Makefile!"); -#endif - return NULL; -} - -static void log_psk(char *label, secret_t *s) -{ - int n = 0; - char buf[BUF_LEN]; - enumerator_t *enumerator; - identification_t *id; - - if (s->ids->get_count(s->ids) == 0) - { - n = snprintf(buf, BUF_LEN, "%%any"); - } - else - { - enumerator = s->ids->create_enumerator(s->ids); - while(enumerator->enumerate(enumerator, &id)) - { - n += snprintf(buf + n, BUF_LEN - n, "%Y ", id); - if (n >= BUF_LEN) - { - n = BUF_LEN - 1; - break; - } - } - enumerator->destroy(enumerator); - } - plog(" loaded %s secret for %.*s", label, n, buf); -} - -static void process_secret(secret_t *s, int whackfd) -{ - err_t ugh = NULL; - - s->kind = SECRET_PSK; /* default */ - if (tokeqword("psk")) - { - log_psk("PSK", s); - - /* preshared key: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in PSK" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("xauth")) - { - s->kind = SECRET_XAUTH; - log_psk("XAUTH", s); - - /* xauth secret: quoted string or ttodata format */ - ugh = !shift()? "unexpected end of record in XAUTH" - : process_psk_secret(&s->u.preshared_secret); - } - else if (tokeqword("rsa")) - { - /* RSA key: the fun begins. - * A braced list of keyword and value pairs. - */ - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad RSA key syntax"; - } - else if (tokeq("{")) - { - ugh = process_rsa_secret(&s->u.private_key); - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_RSA, whackfd); - } - } - else if (tokeqword("ecdsa")) - { - s->kind = SECRET_PUBKEY; - if (!shift()) - { - ugh = "bad ECDSA key syntax"; - } - else - { - ugh = process_keyfile(&s->u.private_key, KEY_ECDSA, whackfd); - } - } - else if (tokeqword("pin")) - { - ugh = process_pin(s, whackfd); - } - else - { - ugh = builddiag("unrecognized key format: %s", tok); - } - - if (ugh != NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s" - , flp->filename, flp->lino, ugh); - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - free(s); - } - else if (flushline("expected record boundary in key")) - { - /* gauntlet has been run: install new secret */ - lock_certs_and_keys("process_secret"); - s->next = secrets; - secrets = s; - unlock_certs_and_keys("process_secrets"); - } -} - -static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */ - -static void process_secret_records(int whackfd) -{ - /* read records from ipsec.secrets and load them into our table */ - for (;;) - { - (void)flushline(NULL); /* silently ditch leftovers, if any */ - if (flp->bdry == B_file) - { - break; - } - flp->bdry = B_none; /* eat the Record Boundary */ - (void)shift(); /* get real first token */ - - if (tokeqword("include")) - { - /* an include directive */ - char fn[MAX_TOK_LEN]; /* space for filename (I hope) */ - char *p = fn; - char *end_prefix = strrchr(flp->filename, '/'); - - if (!shift()) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - - /* if path is relative and including file's pathname has - * a non-empty dirname, prefix this path with that dirname. - */ - if (tok[0] != '/' && end_prefix != NULL) - { - size_t pl = end_prefix - flp->filename + 1; - - /* "clamp" length to prevent problems now; - * will be rediscovered and reported later. - */ - if (pl > sizeof(fn)) - { - pl = sizeof(fn); - } - memcpy(fn, flp->filename, pl); - p += pl; - } - if (flp->cur - tok >= &fn[sizeof(fn)] - p) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: include pathname too long" - , flp->filename, flp->lino); - continue; /* abandon this record */ - } - strcpy(p, tok); - (void) shift(); /* move to Record Boundary, we hope */ - if (flushline("ignoring malformed INCLUDE -- expected Record Boundary after filename")) - { - process_secrets_file(fn, whackfd); - tok = NULL; /* correct, but probably redundant */ - } - } - else - { - /* expecting a list of indices and then the key info */ - secret_t *s = malloc_thing(secret_t); - - zero(s); - s->ids = linked_list_create(); - s->kind = SECRET_PSK; /* default */ - s->u.preshared_secret = chunk_empty; - s->next = NULL; - - for (;;) - { - if (tokeq(":")) - { - /* found key part */ - shift(); /* discard explicit separator */ - process_secret(s, whackfd); - break; - } - else - { - identification_t *id; - - id = identification_create_from_string(tok); - s->ids->insert_last(s->ids, id); - - if (!shift()) - { - /* unexpected Record Boundary or EOF */ - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end" - " of id list", flp->filename, flp->lino); - s->ids->destroy_offset(s->ids, - offsetof(identification_t, destroy)); - free(s); - break; - } - } - } - } - } -} - -static int globugh(const char *epath, int eerrno) -{ - log_errno_routine(eerrno, "problem with secrets file \"%s\"", epath); - return 1; /* stop glob */ -} - -static void process_secrets_file(const char *file_pat, int whackfd) -{ - struct file_lex_position pos; - char **fnp; - - pos.depth = flp == NULL? 0 : flp->depth + 1; - - if (pos.depth > 10) - { - loglog(RC_LOG_SERIOUS, "preshared secrets file \"%s\" nested too deeply", file_pat); - return; - } - -#ifdef HAVE_GLOB_H - /* do globbing */ - { - glob_t globbuf; - int r = glob(file_pat, GLOB_ERR, globugh, &globbuf); - - if (r != 0) - { - switch (r) - { - case GLOB_NOSPACE: - loglog(RC_LOG_SERIOUS, "out of space processing secrets filename \"%s\"", file_pat); - break; - case GLOB_ABORTED: - break; /* already logged */ - case GLOB_NOMATCH: - loglog(RC_LOG_SERIOUS, "no secrets filename matched \"%s\"", file_pat); - break; - default: - loglog(RC_LOG_SERIOUS, "unknown glob error %d", r); - break; - } - globfree(&globbuf); - return; - } - - /* for each file... */ - for (fnp = globbuf.gl_pathv; *fnp != NULL; fnp++) - { - if (lexopen(&pos, *fnp, FALSE)) - { - plog("loading secrets from \"%s\"", *fnp); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } - } - - globfree(&globbuf); - } -#else /* HAVE_GLOB_H */ - /* if glob(3) is not available, try to load pattern directly */ - if (lexopen(&pos, file_pat, FALSE)) - { - plog("loading secrets from \"%s\"", file_pat); - flushline("file starts with indentation (continuation notation)"); - process_secret_records(whackfd); - lexclose(); - } -#endif /* HAVE_GLOB_H */ -} - -void free_preshared_secrets(void) -{ - lock_certs_and_keys("free_preshared_secrets"); - - if (secrets != NULL) - { - secret_t *s, *ns; - - plog("forgetting secrets"); - - for (s = secrets; s != NULL; s = ns) - { - ns = s->next; - s->ids->destroy_offset(s->ids, offsetof(identification_t, destroy)); - - switch (s->kind) - { - case SECRET_PSK: - case SECRET_XAUTH: - free(s->u.preshared_secret.ptr); - break; - case SECRET_PUBKEY: - DESTROY_IF(s->u.private_key); - break; - case SECRET_PIN: - scx_release(s->u.smartcard); - break; - default: - bad_case(s->kind); - } - free(s); - } - secrets = NULL; - } - - unlock_certs_and_keys("free_preshard_secrets"); -} - -void load_preshared_secrets(int whackfd) -{ - free_preshared_secrets(); - (void) process_secrets_file(shared_secrets_file, whackfd); -} - -/* public key machinery - * Note: caller must set dns_auth_level. - */ - -pubkey_t* public_key_from_rsa(public_key_t *key) -{ - pubkey_t *p = malloc_thing(pubkey_t); - - zero(p); - p->id = identification_create_from_string("%any"); /* don't know, doesn't matter */ - p->issuer = NULL; - p->serial = chunk_empty; - p->public_key = key; - - /* note that we return a 1 reference count upon creation: - * invariant: recount > 0. - */ - p->refcnt = 1; - return p; -} - -/* Free a public key record. - * As a convenience, this returns a pointer to next. - */ -pubkey_list_t* free_public_keyentry(pubkey_list_t *p) -{ - pubkey_list_t *nxt = p->next; - - if (p->key != NULL) - { - unreference_key(&p->key); - } - free(p); - return nxt; -} - -void free_public_keys(pubkey_list_t **keys) -{ - while (*keys != NULL) - { - *keys = free_public_keyentry(*keys); - } -} - -/* root of chained public key list */ - -pubkey_list_t *pubkeys = NULL; /* keys from ipsec.conf */ - -void free_remembered_public_keys(void) -{ - free_public_keys(&pubkeys); -} - -/** - * Transfer public keys from *keys list to front of pubkeys list - */ -void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR -, pubkey_list_t **keys -#endif /* USE_KEYRR */ -) -{ - { - struct gw_info *gwp; - - for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) - { - pubkey_list_t *pl = malloc_thing(pubkey_list_t); - - pl->key = gwp->key; /* note: this is a transfer */ - gwp->key = NULL; /* really, it is! */ - pl->next = pubkeys; - pubkeys = pl; - } - } - -#ifdef USE_KEYRR - { - pubkey_list_t **pp = keys; - - while (*pp != NULL) - { - pp = &(*pp)->next; - } - *pp = pubkeys; - pubkeys = *keys; - *keys = NULL; - } -#endif /* USE_KEYRR */ -} - - -static void install_public_key(pubkey_t *pk, pubkey_list_t **head) -{ - pubkey_list_t *p = malloc_thing(pubkey_list_t); - - /* install new key at front */ - p->key = reference_key(pk); - p->next = *head; - *head = p; -} - -void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial) -{ - pubkey_list_t **pp, *p; - pubkey_t *pk; - key_type_t pk_type; - - for (pp = &pubkeys; (p = *pp) != NULL; ) - { - pk = p->key; - pk_type = pk->public_key->get_type(pk->public_key); - - if (id->equals(id, pk->id) && pk_type == type - && (issuer == NULL || pk->issuer == NULL - || issuer->equals(issuer, pk->issuer)) - && (serial.ptr == NULL || chunk_equals(serial, pk->serial))) - { - *pp = free_public_keyentry(p); - } - else - { - pp = &p->next; - } - } -} - -pubkey_t* reference_key(pubkey_t *pk) -{ - DBG(DBG_CONTROLMORE, - DBG_log(" ref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - pk->refcnt++; - return pk; -} - -void unreference_key(pubkey_t **pkp) -{ - pubkey_t *pk = *pkp; - - if (pk == NULL) - { - return; - } - - DBG(DBG_CONTROLMORE, - DBG_log("unref key: %p %p cnt %d '%Y'", - pk, pk->public_key, pk->refcnt, pk->id) - ) - - /* cancel out the pointer */ - *pkp = NULL; - - passert(pk->refcnt != 0); - pk->refcnt--; - if (pk->refcnt == 0) - { - free_public_key(pk); - } -} - -bool add_public_key(identification_t *id, enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, chunk_t rfc3110_key, - pubkey_list_t **head) -{ - public_key_t *key = NULL; - pubkey_t *pk; - - /* first: algorithm-specific decoding of key chunk */ - switch (alg) - { - case PUBKEY_ALG_RSA: - key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, - BUILD_BLOB_DNSKEY, rfc3110_key, - BUILD_END); - if (key == NULL) - { - return FALSE; - } - break; - default: - bad_case(alg); - } - - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = key; - pk->id = id->clone(id); - pk->dns_auth_level = dns_auth_level; - pk->until_time = UNDEFINED_TIME; - pk->issuer = NULL; - pk->serial = chunk_empty; - install_public_key(pk, head); - return TRUE; -} - -/** - * Extract id and public key a certificate and insert it into a pubkeyrec - */ -void add_public_key_from_cert(cert_t *cert , time_t until, - enum dns_auth_level dns_auth_level) -{ - certificate_t *certificate = cert->cert; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = NULL; - identification_t *id; - chunk_t serialNumber = chunk_empty; - pubkey_t *pk; - key_type_t pk_type; - - /* ID type: ID_DER_ASN1_DN (X.509 subject field) */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->public_key = certificate->get_public_key(certificate); - pk_type = pk->public_key->get_type(pk->public_key); - pk->id = subject->clone(subject); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - - issuer = certificate->get_issuer(certificate); - serialNumber = x509->get_serial(x509); - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - } - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - - if (certificate->get_type(certificate) == CERT_X509) - { - x509_t *x509 = (x509_t*)certificate; - enumerator_t *enumerator; - - /* insert all subjectAltNames from X.509 certificates */ - enumerator = x509->create_subjectAltName_enumerator(x509); - while (enumerator->enumerate(enumerator, &id)) - { - if (id->get_type(id) != ID_ANY) - { - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = id->clone(id); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - pk->issuer = issuer->clone(issuer); - pk->serial = chunk_clone(serialNumber); - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } - } - enumerator->destroy(enumerator); - } - else - { - pgp_certificate_t *pgp_cert = (pgp_certificate_t*)certificate; - chunk_t fingerprint = pgp_cert->get_fingerprint(pgp_cert); - - /* add v3 or v4 PGP fingerprint */ - pk = malloc_thing(pubkey_t); - zero(pk); - pk->id = identification_create_from_encoding(ID_KEY_ID, fingerprint); - pk->public_key = certificate->get_public_key(certificate); - pk->dns_auth_level = dns_auth_level; - pk->until_time = until; - delete_public_keys(pk->id, pk_type, pk->issuer, pk->serial); - install_public_key(pk, &pubkeys); - } -} - -/* when a X.509 certificate gets revoked, all instances of - * the corresponding public key must be removed - */ -void remove_x509_public_key(const cert_t *cert) -{ - public_key_t *revoked_key = cert->cert->get_public_key(cert->cert); - pubkey_list_t *p, **pp; - - p = pubkeys; - pp = &pubkeys; - - while(p != NULL) - { - if (revoked_key->equals(revoked_key, p->key->public_key)) - { - /* remove p from list and free memory */ - *pp = free_public_keyentry(p); - loglog(RC_LOG_SERIOUS, "invalid public key deleted"); - } - else - { - pp = &p->next; - } - p =*pp; - } - revoked_key->destroy(revoked_key); -} - -/* - * list all public keys in the chained list - */ -void list_public_keys(bool utc) -{ - pubkey_list_t *p = pubkeys; - chunk_t serial; - - if (p != NULL) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of Public Keys:"); - } - - while (p != NULL) - { - pubkey_t *key = p->key; - public_key_t *public = key->public_key; - chunk_t keyid; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, " identity: '%Y'", key->id); - whack_log(RC_COMMENT, " pubkey: %N %4d bits, until %T %s", - key_type_names, public->get_type(public), - public->get_keysize(public), - &key->until_time, utc, - check_expiry(key->until_time, PUBKEY_WARNING_INTERVAL, TRUE)); - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - whack_log(RC_COMMENT," keyid: %#B", &keyid); - } - if (key->issuer) - { - whack_log(RC_COMMENT," issuer: \"%Y\"", key->issuer); - } - if (key->serial.len) - { - serial = chunk_skip_zero(key->serial); - whack_log(RC_COMMENT," serial: %#B", &serial); - } - p = p->next; - } -} diff --git a/src/pluto/keys.h b/src/pluto/keys.h deleted file mode 100644 index 73cc21392..000000000 --- a/src/pluto/keys.h +++ /dev/null @@ -1,93 +0,0 @@ -/* mechanisms for preshared keys (public, private, and preshared secrets) - * Copyright (C) 1998-2002 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen, Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _KEYS_H -#define _KEYS_H - -#include -#include -#include - -#include "certs.h" -#include "connections.h" - -#ifndef SHARED_SECRETS_FILE -# define SHARED_SECRETS_FILE IPSEC_CONFDIR "/ipsec.secrets" -#endif - -const char *shared_secrets_file; - -extern void load_preshared_secrets(int whackfd); -extern void free_preshared_secrets(void); - -extern void xauth_defaults(void); - -extern bool get_xauth_secret(identification_t *user, identification_t *server, - chunk_t *secret); -extern const chunk_t *get_preshared_secret(const connection_t *c); -extern private_key_t *get_private_key(const connection_t *c); -extern private_key_t *get_x509_private_key(const cert_t *cert); - -/* public key machinery */ - -typedef struct pubkey pubkey_t; - -struct pubkey { - identification_t *id; - unsigned refcnt; /* reference counted! */ - enum dns_auth_level dns_auth_level; - char *dns_sig; - time_t last_tried_time, last_worked_time, until_time; - identification_t *issuer; - chunk_t serial; - public_key_t *public_key; -}; - -typedef struct pubkey_list pubkey_list_t; - -struct pubkey_list { - pubkey_t *key; - pubkey_list_t *next; -}; - -extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */ - -extern pubkey_t *public_key_from_rsa(public_key_t *key); -extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p); -extern void free_public_keys(pubkey_list_t **keys); -extern void free_remembered_public_keys(void); -extern void delete_public_keys(identification_t *id, key_type_t type, - identification_t *issuer, chunk_t serial); -extern pubkey_t *reference_key(pubkey_t *pk); -extern void unreference_key(pubkey_t **pkp); -extern bool add_public_key(identification_t *id, - enum dns_auth_level dns_auth_level, - enum pubkey_alg alg, - chunk_t rfc3110_key, - pubkey_list_t **head); -extern bool has_private_key(cert_t *cert); -extern void add_public_key_from_cert(cert_t *cert, time_t until, - enum dns_auth_level dns_auth_level); -extern void remove_x509_public_key(const cert_t *cert); -extern void list_public_keys(bool utc); - -struct gw_info; /* forward declaration of tag (defined in dnskey.h) */ -extern void transfer_to_public_keys(struct gw_info *gateways_from_dns -#ifdef USE_KEYRR - , pubkey_list_t **keys -#endif /* USE_KEYRR */ - ); - -#endif /* _KEYS_H */ diff --git a/src/pluto/lex.c b/src/pluto/lex.c deleted file mode 100644 index d5ebdaba9..000000000 --- a/src/pluto/lex.c +++ /dev/null @@ -1,211 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ -#include "lex.h" - -struct file_lex_position *flp = NULL; - -/* Open a file for lexical processing. - * new_flp and name must point into storage with will live - * at least until the file is closed. - */ -bool -lexopen(struct file_lex_position *new_flp, const char *name, bool optional) -{ - FILE *f = fopen(name, "r"); - - if (f == NULL) - { - if (!optional || errno != ENOENT) - log_errno((e, "could not open \"%s\"", name)); - return FALSE; - } - else - { - new_flp->previous = flp; - flp = new_flp; - flp->filename = name; - flp->fp = f; - flp->lino = 0; - flp->bdry = B_none; - - flp->cur = flp->buffer; /* nothing loaded yet */ - flp->under = *flp->cur = '\0'; - - (void) shift(); /* prime tok */ - return TRUE; - } -} - -void -lexclose(void) -{ - fclose(flp->fp); - flp = flp->previous; -} - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -bool -shift(void) -{ - char *p = flp->cur; - char *sor = NULL; /* start of record for any new lines */ - - passert(flp->bdry == B_none); - - *p = flp->under; - flp->under = '\0'; - - for (;;) - { - switch (*p) - { - case '\0': /* end of line */ - case '#': /* comment to end of line: treat as end of line */ - /* get the next line */ - if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL) - { - flp->bdry = B_file; - tok = flp->cur = NULL; - return FALSE; - } - else - { - /* strip trailing whitespace, including \n */ - - for (p = flp->buffer+strlen(flp->buffer)-1 - ; p>flp->buffer && isspace(p[-1]); p--) - ; - *p = '\0'; - - flp->lino++; - sor = p = flp->buffer; - } - break; /* try again for a token */ - - case ' ': /* whitespace */ - case '\t': - p++; - break; /* try again for a token */ - - case '"': /* quoted token */ - case '\'': - if (p != sor) - { - /* we have a quoted token: note and advance to its end */ - tok = p; - p = strchr(p+1, *p); - if (p == NULL) - { - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string" - , flp->filename, flp->lino); - p = tok + strlen(tok); - } - else - { - p++; /* include delimiter in token */ - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - /* FALL THROUGH */ - default: - if (p != sor) - { - /* we seem to have a token: note and advance to its end */ - tok = p; - - if (p[0] == '0' && p[1] == 't') - { - /* 0t... token goes to end of line */ - p += strlen(p); - } - else - { - /* "ordinary" token: up to whitespace or end of line */ - do { - p++; - } while (*p != '\0' && !isspace(*p)) - ; - - /* fudge to separate ':' from a preceding adjacent token */ - if (p-1 > tok && p[-1] == ':') - p--; - } - - /* remember token delimiter and replace with '\0' */ - flp->under = *p; - *p = '\0'; - flp->cur = p; - return TRUE; - } - - /* we have a start-of-record: return it, deferring "real" token */ - flp->bdry = B_record; - tok = NULL; - flp->under = *p; - flp->cur = p; - return FALSE; - } - } -} - -/* ensures we are at a Record (or File) boundary, optionally warning if not */ - -bool -flushline(const char *m) -{ - if (flp->bdry != B_none) - { - return TRUE; - } - else - { - if (m != NULL) - loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m); - do {} while (shift()); - return FALSE; - } -} diff --git a/src/pluto/lex.h b/src/pluto/lex.h deleted file mode 100644 index aa0be7829..000000000 --- a/src/pluto/lex.h +++ /dev/null @@ -1,50 +0,0 @@ -/* lexer (lexical analyzer) for control files - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#define MAX_TOK_LEN 2048 /* includes terminal '\0' */ -struct file_lex_position -{ - int depth; /* how deeply we are nested */ - const char *filename; - FILE *fp; - enum { B_none, B_record, B_file } bdry; /* current boundary */ - int lino; /* line number in file */ - char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */ - char *cur; /* cursor */ - char under; /* except in shift(): character originally at *cur */ - struct file_lex_position *previous; -}; - -extern struct file_lex_position *flp; - -extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional); -extern void lexclose(void); - - -/* Token decoding: shift() loads the next token into tok. - * Iff a token starts at the left margin, it is considered - * to be the first in a record. We create a special condition, - * Record Boundary (analogous to EOF), just before such a token. - * We are unwilling to shift through a record boundary: - * it must be overridden first. - * Returns FALSE iff Record Boundary or EOF (i.e. no token); - * tok will then be NULL. - */ - -extern char *tok; -#define tokeq(s) (streq(tok, (s))) -#define tokeqword(s) (strcasecmp(tok, (s)) == 0) - -extern bool shift(void); -extern bool flushline(const char *m); diff --git a/src/pluto/log.c b/src/pluto/log.c deleted file mode 100644 index f6fa226d5..000000000 --- a/src/pluto/log.c +++ /dev/null @@ -1,946 +0,0 @@ -/* error logging functions - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* used only if MSG_NOSIGNAL not defined */ -#include -#include -#include -#include - -#ifdef ANDROID -#include -#endif - -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "myid.h" -#include "kernel.h" -#include "whack.h" -#include "whack_attribute.h" -#include "timer.h" - -/* close one per-peer log */ -static void perpeer_logclose(connection_t *c); /* forward */ - - -bool - log_to_stderr = TRUE, /* should log go to stderr? */ - log_to_syslog = TRUE, /* should log go to syslog? */ - log_to_perpeer= FALSE; /* should log go to per-IP file? */ - -bool - logged_txt_warning = FALSE; /* should we complain about finding KEY? */ - -/* should we complain when we find no local id */ -bool - logged_myid_fqdn_txt_warning = FALSE, - logged_myid_ip_txt_warning = FALSE, - logged_myid_fqdn_key_warning = FALSE, - logged_myid_ip_key_warning = FALSE; - -/* may include trailing / */ -const char *base_perpeer_logdir = PERPEERLOGDIR; -static int perpeer_count = 0; - -/* from sys/queue.h */ -static TAILQ_HEAD(perpeer, connection) perpeer_list; - - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -int whack_log_fd = NULL_FD; /* only set during whack_handle() */ -struct state *cur_state = NULL; /* current state, for diagnostics */ -connection_t *cur_connection = NULL; /* current connection, for diagnostics */ -const ip_address *cur_from = NULL; /* source of current current message */ -u_int16_t cur_from_port; /* host order */ - -/** - * pluto dbg function for libstrongswan - */ -static void pluto_dbg(debug_t group, level_t level, char *fmt, ...) -{ - int priority = LOG_INFO; - int debug_level; - char buffer[8192]; - char *current = buffer, *next; - va_list args; - - if (cur_debugging & DBG_PRIVATE) - { - debug_level = 4; - } - else if (cur_debugging & DBG_RAW) - { - debug_level = 3; - } - else if (cur_debugging & DBG_PARSING) - { - debug_level = 2; - } - else - { - debug_level = 1; - } - - if (level <= debug_level) - { - va_start(args, fmt); - - if (log_to_stderr) - { - if (level > 1) - { - fprintf(stderr, "| "); - } - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - } - if (log_to_syslog -#ifdef ANDROID - || TRUE -#endif - ) - { - /* write in memory buffer first */ - vsnprintf(buffer, sizeof(buffer), fmt, args); - - /* do a syslog with every line */ - while (current) - { - next = strchr(current, '\n'); - if (next) - { - *(next++) = '\0'; - } - syslog(priority, "%s%s\n", (level > 1)? "| ":"", current); -#ifdef ANDROID - __android_log_print(level > 1 ? ANDROID_LOG_DEBUG - : ANDROID_LOG_INFO, "pluto", - "%s%s\n", level > 1 ? "| " : "", current); -#endif - current = next; - } - } - va_end(args); - } -} - -void -init_log(const char *program) -{ - /* enable pluto debugging hook for libstrongswan */ - dbg = pluto_dbg; - - if (log_to_stderr) - { - setbuf(stderr, NULL); - } - if (log_to_syslog) - { - openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV); - } - TAILQ_INIT(&perpeer_list); -} - -void -close_peerlog(void) -{ - /* exit if the queue has not been initialized */ - if (perpeer_list.tqh_first == NULL) - return; - - /* end of queue is given by pointer to "HEAD" */ - while (TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list) - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); -} - -void -close_log(void) -{ - if (log_to_syslog) - closelog(); - - close_peerlog(); -} - -/* Sanitize character string in situ: turns dangerous characters into \OOO. - * With a bit of work, we could use simpler reps for \\, \r, etc., - * but this is only to protect against something that shouldn't be used. - * Truncate resulting string to what fits in buffer. - */ -static size_t -sanitize(char *buf, size_t size) -{ -# define UGLY_WIDTH 4 /* width for ugly character: \OOO */ - size_t len; - size_t added = 0; - char *p; - - passert(size >= UGLY_WIDTH); /* need room to swing cat */ - - /* find right side of string to be sanitized and count - * number of columns to be added. Stop on end of string - * or lack of room for more result. - */ - for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; ) - { - unsigned char c = *p++; - - if (c == '\\' || !isprint(c)) - added += UGLY_WIDTH - 1; - } - - /* at this point, p points after last original character to be - * included. added is how many characters are added to sanitize. - * so p[added] will point after last sanitized character. - */ - - p[added] = '\0'; - len = &p[added] - buf; - - /* scan backwards, copying characters to their new home - * and inserting the expansions for ugly characters. - * It is finished when no more shifting is required. - * This is a predecrement loop. - */ - while (added != 0) - { - char fmtd[UGLY_WIDTH + 1]; - unsigned char c; - - while ((c = *--p) != '\\' && isprint(c)) - p[added] = c; - added -= UGLY_WIDTH - 1; - snprintf(fmtd, sizeof(fmtd), "\\%03o", c); - memcpy(p + added, fmtd, UGLY_WIDTH); - } - return len; -# undef UGLY_WIDTH -} - -/* format a string for the log, with suitable prefixes. - * A format starting with ~ indicates that this is a reprocessing - * of the message, so prefixing and quoting is suppressed. - */ -static void -fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap) -{ - bool reproc = *fmt == '~'; - size_t ps; - connection_t *c = cur_state != NULL ? cur_state->st_connection - : cur_connection; - - buf[0] = '\0'; - if (reproc) - fmt++; /* ~ at start of format suppresses this prefix */ - else if (c != NULL) - { - /* start with name of connection */ - char *const be = buf + buf_len; - char *bp = buf; - - snprintf(bp, be - bp, "\"%s\"", c->name); - bp += strlen(bp); - - /* if it fits, put in any connection instance information */ - if (be - bp > CONN_INST_BUF) - { - fmt_conn_instance(c, bp); - bp += strlen(bp); - } - - if (cur_state != NULL) - { - /* state number */ - snprintf(bp, be - bp, " #%lu", cur_state->st_serialno); - bp += strlen(bp); - } - snprintf(bp, be - bp, ": "); - } - else if (cur_from != NULL) - { - /* peer's IP address */ - /* Note: must not use ip_str() because our caller might! */ - char ab[ADDRTOT_BUF]; - - (void) addrtot(cur_from, 0, ab, sizeof(ab)); - snprintf(buf, buf_len, "packet from %s:%u: " - , ab, (unsigned)cur_from_port); - } - - ps = strlen(buf); - vsnprintf(buf + ps, buf_len - ps, fmt, ap); - if (!reproc) - (void)sanitize(buf, buf_len); -} - -static void -perpeer_logclose(connection_t *c) -{ - /* only free/close things if we had used them! */ - if (c->log_file != NULL) - { - passert(perpeer_count > 0); - - TAILQ_REMOVE(&perpeer_list, c, log_link); - perpeer_count--; - fclose(c->log_file); - c->log_file=NULL; - } -} - -void -perpeer_logfree(connection_t *c) -{ - perpeer_logclose(c); - if (c->log_file_name != NULL) - { - free(c->log_file_name); - c->log_file_name = NULL; - c->log_file_err = FALSE; - } -} - -/* open the per-peer log */ -static void -open_peerlog(connection_t *c) -{ - syslog(LOG_INFO, "opening log file for conn %s", c->name); - - if (c->log_file_name == NULL) - { - char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF]; - int peernamelen, lf_len; - - addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername)); - peernamelen = strlen(peername); - - /* copy IP address, turning : and . into / */ - { - char ch, *p, *q; - - p = peername; - q = dname; - do { - ch = *p++; - if (ch == '.' || ch == ':') - ch = '/'; - *q++ = ch; - } while (ch != '\0'); - } - - lf_len = peernamelen * 2 - + strlen(base_perpeer_logdir) - + sizeof("//.log") - + 1; - c->log_file_name = malloc(lf_len); - - fprintf(stderr, "base dir |%s| dname |%s| peername |%s|" - , base_perpeer_logdir, dname, peername); - snprintf(c->log_file_name, lf_len, "%s/%s/%s.log" - , base_perpeer_logdir, dname, peername); - - syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name); - } - - /* now open the file, creating directories if necessary */ - - { /* create the directory */ - char *dname; - int bpl_len = strlen(base_perpeer_logdir); - char *slashloc; - - dname = clone_str(c->log_file_name); - dname = dirname(dname); - - if (access(dname, W_OK) != 0) - { - if (errno != ENOENT) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "can not write to %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - } - - /* directory does not exist, walk path creating dirs */ - /* start at base_perpeer_logdir */ - slashloc = dname + bpl_len; - slashloc++; /* since, by construction there is a slash - right there */ - - while (*slashloc != '\0') - { - char saveslash; - - /* look for next slash */ - while (*slashloc != '\0' && *slashloc != '/') slashloc++; - - saveslash = *slashloc; - - *slashloc = '\0'; - - if (mkdir(dname, 0750) != 0 && errno != EEXIST) - { - syslog(LOG_CRIT, "can not create dir %s: %s" - , dname, strerror(errno)); - c->log_file_err = TRUE; - free(dname); - return; - } - syslog(LOG_DEBUG, "created new directory %s", dname); - *slashloc = saveslash; - slashloc++; - } - } - free(dname); - } - - c->log_file = fopen(c->log_file_name, "a"); - if (c->log_file == NULL) - { - if (c->log_file_err) - { - syslog(LOG_CRIT, "logging system can not open %s: %s" - , c->log_file_name, strerror(errno)); - c->log_file_err = TRUE; - } - return; - } - - /* look for a connection to close! */ - while (perpeer_count >= MAX_PEERLOG_COUNT) - { - /* can not be NULL because perpeer_count > 0 */ - passert(TAILQ_LAST(&perpeer_list, perpeer) != (void *)&perpeer_list); - - perpeer_logclose(TAILQ_LAST(&perpeer_list, perpeer)); - } - - /* insert this into the list */ - TAILQ_INSERT_HEAD(&perpeer_list, c, log_link); - passert(c->log_file != NULL); - perpeer_count++; -} - -/* log a line to cur_connection's log */ -static void -peerlog(const char *prefix, const char *m) -{ - if (cur_connection == NULL) - { - /* we can not log it in this case. Oh well. */ - return; - } - - if (cur_connection->log_file == NULL) - { - open_peerlog(cur_connection); - } - - /* despite our attempts above, we may not be able to open the file. */ - if (cur_connection->log_file != NULL) - { - char datebuf[32]; - time_t n; - struct tm *t; - - time(&n); - t = localtime(&n); - - strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t); - fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m); - - /* now move it to the front of the list */ - TAILQ_REMOVE(&perpeer_list, cur_connection, log_link); - TAILQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link); - } -} - -void -plog(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(RC_LOG, "~%s", m); -} - -void -loglog(int mess_no, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "%s\n", m); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m); -#endif - - whack_log(mess_no, "~%s", m); -} - -void -log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "ERROR: %s. Errno %d: %s\n", - m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~ERROR: %s. Errno %d: %s", m, e, strerror(e)); -} - -void -exit_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s\n", m); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s", m); - if (log_to_perpeer) - peerlog("FATAL ERROR: ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s\n", m); -#endif - - whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m); - - exit_pluto(1); -} - -void -exit_log_errno_routine(int e, const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - fmt_log(m, sizeof(m), message, args); - va_end(args); - - if (log_to_stderr) - fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e)); - if (log_to_syslog) - syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - if (log_to_perpeer) - peerlog(strerror(e), m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_ERROR, "pluto", "FATAL ERROR: %s. " - "Errno %d: %s\n", m, e, strerror(e)); -#endif - - whack_log(RC_LOG_SERIOUS - , "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e)); - - exit_pluto(1); -} - -/* emit message to whack. - * form is "ddd statename text" where - * - ddd is a decimal status code (RC_*) as described in whack.h - * - text is a human-readable annotation - */ -#ifdef DEBUG -static volatile sig_atomic_t dying_breath = FALSE; -#endif - -void -whack_log(int mess_no, const char *message, ...) -{ - int wfd = whack_log_fd != NULL_FD ? whack_log_fd - : cur_state != NULL ? cur_state->st_whack_sock - : NULL_FD; - - if (wfd != NULL_FD -#ifdef DEBUG - || dying_breath -#endif - ) - { - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - int prelen = snprintf(m, sizeof(m), "%03d ", mess_no); - - passert(prelen >= 0); - - va_start(args, message); - fmt_log(m+prelen, sizeof(m)-prelen, message, args); - va_end(args); - -#if DEBUG - if (dying_breath) - { - /* status output copied to log */ - if (log_to_stderr) - fprintf(stderr, "%s\n", m + prelen); - if (log_to_syslog) - syslog(LOG_WARNING, "%s", m + prelen); - if (log_to_perpeer) - peerlog("", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_WARN, "pluto", "%s\n", m + prelen); -#endif - } -#endif - - if (wfd != NULL_FD) - { - /* write to whack socket, but suppress possible SIGPIPE */ - size_t len = strlen(m); -#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */ - m[len] = '\n'; /* don't need NUL, do need NL */ - (void) send(wfd, m, len + 1, MSG_NOSIGNAL); -#else /* !MSG_NOSIGNAL */ - int r; - struct sigaction act - , oldact; - - m[len] = '\n'; /* don't need NUL, do need NL */ - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; /* no nothing */ - r = sigaction(SIGPIPE, &act, &oldact); - passert(r == 0); - - (void) write(wfd, m, len + 1); - - r = sigaction(SIGPIPE, &oldact, NULL); - passert(r == 0); -#endif /* !MSG_NOSIGNAL */ - } - } -} - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -char diag_space[sizeof(diag_space)]; - -err_t -builddiag(const char *fmt, ...) -{ - static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */ - char t[sizeof(diag_space)]; /* build result here first */ - va_list args; - - va_start(args, fmt); - t[0] = '\0'; /* in case nothing terminates string */ - vsnprintf(t, sizeof(t), fmt, args); - va_end(args); - strcpy(diag_space, t); - return diag_space; -} - -/* Debugging message support */ - -#ifdef DEBUG - -void -switch_fail(int n, const char *file_str, unsigned long line_no) -{ - char buf[30]; - - snprintf(buf, sizeof(buf), "case %d unexpected", n); - passert_fail(buf, file_str, line_no); -} - -void -passert_fail(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str); - if (!dying_breath) - { - dying_breath = TRUE; - show_status(TRUE, NULL); - } - abort(); /* exiting correctly doesn't always work */ -} - -void -pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no) -{ - /* we will get a possibly unplanned prefix. Hope it works */ - loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str); -} - -lset_t - base_debugging = DBG_NONE, /* default to reporting nothing */ - cur_debugging = DBG_NONE; - -void -extra_debugging(const connection_t *c) -{ - if(c == NULL) - { - reset_debugging(); - return; - } - - if (c!= NULL && c->extra_debugging != 0) - { - plog("enabling for connection: %s" - , bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging)); - cur_debugging |= c->extra_debugging; - } -} - -/* log a debugging message (prefixed by "| ") */ - -void -DBG_log(const char *message, ...) -{ - va_list args; - char m[LOG_WIDTH]; /* longer messages will be truncated */ - - va_start(args, message); - vsnprintf(m, sizeof(m), message, args); - va_end(args); - - (void)sanitize(m, sizeof(m)); - - if (log_to_stderr) - fprintf(stderr, "| %s\n", m); - if (log_to_syslog) - syslog(LOG_DEBUG, "| %s", m); - if (log_to_perpeer) - peerlog("| ", m); -#ifdef ANDROID - __android_log_print(ANDROID_LOG_DEBUG, "pluto", "| %s\n", m); -#endif -} - -/* dump raw bytes in hex to stderr (for lack of any better destination) */ - -void -DBG_dump(const char *label, const void *p, size_t len) -{ -# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */ -# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1) - char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH]; - char *bp; - const unsigned char *cp = p; - - bp = buf; - - if (label != NULL && label[0] != '\0') - { - /* Handle the label. Care must be taken to avoid buffer overrun. */ - size_t llen = strlen(label); - - if (llen + 1 > sizeof(buf)) - { - DBG_log("%s", label); - } - else - { - strcpy(buf, label); - if (buf[llen-1] == '\n') - { - buf[llen-1] = '\0'; /* get rid of newline */ - DBG_log("%s", buf); - } - else if (llen < DUMP_LABEL_WIDTH) - { - bp = buf + llen; - } - else - { - DBG_log("%s", buf); - } - } - } - - do { - int i, j; - - for (i = 0; len!=0 && i!=4; i++) - { - *bp++ = ' '; - for (j = 0; len!=0 && j!=4; len--, j++) - { - static const char hexdig[] = "0123456789abcdef"; - - *bp++ = ' '; - *bp++ = hexdig[(*cp >> 4) & 0xF]; - *bp++ = hexdig[*cp & 0xF]; - cp++; - } - } - *bp = '\0'; - DBG_log("%s", buf); - bp = buf; - } while (len != 0); -# undef DUMP_LABEL_WIDTH -# undef DUMP_WIDTH -} - -#endif /* DEBUG */ - -static void show_loaded_plugins() -{ - whack_log(RC_COMMENT, "loaded plugins: %s", - lib->plugins->loaded_plugins(lib->plugins)); -} - -void show_status(bool all, const char *name) -{ - if (all) - { - whack_log(RC_COMMENT, "Status of IKEv1 pluto daemon (strongSwan "VERSION"):"); - show_ifaces_status(); - show_myid_status(); - show_loaded_plugins(); - show_debug_status(); - show_pools(name); - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ - } - show_connections_status(all, name); - show_states_status(all, name); -} - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -const char * -ip_str(const ip_address *src) -{ - static char buf[ADDRTOT_BUF]; - - addrtot(src, 0, buf, sizeof(buf)); - return buf; -} - -/* - * a routine that attempts to schedule itself daily. - * - */ - -void -daily_log_reset(void) -{ - /* now perform actions */ - logged_txt_warning = FALSE; - - logged_myid_fqdn_txt_warning = FALSE; - logged_myid_ip_txt_warning = FALSE; - logged_myid_fqdn_key_warning = FALSE; - logged_myid_ip_key_warning = FALSE; -} - -void -daily_log_event(void) -{ - struct tm lt; - time_t t, interval; - - /* attempt to schedule oneself to midnight, local time - * do this by getting seconds in the day, and delaying - * by 86400 - 3600*hours - 60*minutes - seconds. - */ - time(&t); - localtime_r(&t, <); - interval = 3600 * (24 - lt.tm_hour) - 60 * lt.tm_min - lt.tm_sec; - - event_schedule(EVENT_LOG_DAILY, interval, NULL); - daily_log_reset(); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/log.h b/src/pluto/log.h deleted file mode 100644 index 52c01bbd4..000000000 --- a/src/pluto/log.h +++ /dev/null @@ -1,234 +0,0 @@ -/* logging definitions - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#define LOG_WIDTH 1024 /* roof of number of chars in log line */ - -#ifndef PERPEERLOGDIR -#define PERPEERLOGDIR "/var/log/pluto/peer" -#endif - -/* our versions of assert: log result */ - -#ifdef DEBUG - -extern void passert_fail(const char *pred_str - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -extern void pexpect_log(const char *pred_str - , const char *file_str, unsigned long line_no); - -# define impossible() passert_fail("impossible", __FILE__, __LINE__) - -extern void switch_fail(int n - , const char *file_str, unsigned long line_no) NEVER_RETURNS; - -# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__) - -# define passert(pred) { \ - if (!(pred)) \ - passert_fail(#pred, __FILE__, __LINE__); \ - } - -# define pexpect(pred) { \ - if (!(pred)) \ - pexpect_log(#pred, __FILE__, __LINE__); \ - } - -/* assert that an err_t is NULL; evaluate exactly once */ -# define happy(x) { \ - err_t ugh = x; \ - if (ugh != NULL) \ - passert_fail(ugh, __FILE__, __LINE__); \ - } - -#else /*!DEBUG*/ - -# define impossible() abort() -# define bad_case(n) abort() -# define passert(pred) { } /* do nothing */ -# define happy(x) { (void) x; } /* evaluate non-judgementally */ - -#endif /*!DEBUG*/ - - -extern bool - log_to_stderr, /* should log go to stderr? */ - log_to_syslog, /* should log go to syslog? */ - log_to_perpeer; /* should log go to per-IP file? */ - -extern const char *base_perpeer_logdir; - -/* maximum number of files to keep open for per-peer log files */ -#define MAX_PEERLOG_COUNT 16 - -/* Context for logging. - * - * Global variables: must be carefully adjusted at transaction boundaries! - * All are to be left in RESET condition and will be checked. - * There are several pairs of routines to set and reset them. - * If the context provides a whack file descriptor, messages - * should be copied to it -- see whack_log() - */ -extern int whack_log_fd; /* only set during whack_handle() */ -extern struct state *cur_state; /* current state, for diagnostics */ -extern struct connection *cur_connection; /* current connection, for diagnostics */ -extern const ip_address *cur_from; /* source of current current message */ -extern u_int16_t cur_from_port; /* host order */ - -#ifdef DEBUG - - extern lset_t cur_debugging; /* current debugging level */ - - extern void extra_debugging(const struct connection *c); - -# define reset_debugging() { cur_debugging = base_debugging; } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL \ - && cur_debugging == base_debugging) - -#else /*!DEBUG*/ - -# define extra_debugging(c) { } - -# define reset_debugging() { } - -# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \ - && cur_state == NULL \ - && cur_connection == NULL \ - && cur_from == NULL) - -#endif /*!DEBUG*/ - -#define reset_globals() { \ - whack_log_fd = NULL_FD; \ - cur_state = NULL; \ - cur_from = NULL; \ - reset_cur_connection(); \ - } - - -#define set_cur_connection(c) { \ - cur_connection = (c); \ - extra_debugging(c); \ - } - -#define reset_cur_connection() { \ - cur_connection = NULL; \ - reset_debugging(); \ - } - - -#define set_cur_state(s) { \ - cur_state = (s); \ - extra_debugging((s)->st_connection); \ - } - -#define reset_cur_state() { \ - cur_state = NULL; \ - reset_debugging(); \ - } - -extern void init_log(const char *program); -extern void close_log(void); -extern void plog(const char *message, ...) PRINTF_LIKE(1); -extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS; - -/* close of all per-peer logging */ -extern void close_peerlog(void); - -/* free all per-peer log resources */ -extern void perpeer_logfree(struct connection *c); - - - -/* the following routines do a dance to capture errno before it is changed - * A call must doubly parenthesize the argument list (no varargs macros). - * The first argument must be "e", the local variable that captures errno. - */ -#define log_errno(a) { int e = errno; log_errno_routine a; } -extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2); -#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; } -extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS; - -extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* Log to both main log and whack log - * Much like log, actually, except for specifying mess_no. - */ -extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2); - -/* show status, usually on whack log */ -extern void show_status(bool all, const char *name); - -/* Build up a diagnostic in a static buffer. - * Although this would be a generally useful function, it is very - * hard to come up with a discipline that prevents different uses - * from interfering. It is intended that by limiting it to building - * diagnostics, we will avoid this problem. - * Juggling is performed to allow an argument to be a previous - * result: the new string may safely depend on the old one. This - * restriction is not checked in any way: violators will produce - * confusing results (without crashing!). - */ -extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */ -extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1); - -#ifdef DEBUG - -extern lset_t base_debugging; /* bits selecting what to report */ - -#define DBGP(cond) (cur_debugging & (cond)) -#define DBG(cond, action) { if (DBGP(cond)) { action ; } } - -extern void DBG_log(const char *message, ...) PRINTF_LIKE(1); -extern void DBG_dump(const char *label, const void *p, size_t len); -#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len) - -#else /*!DEBUG*/ - -#define DBG(cond, action) { } /* do nothing */ - -#endif /*!DEBUG*/ - -#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len)) -#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch)) - - -/* ip_str: a simple to use variant of addrtot. - * It stores its result in a static buffer. - * This means that newer calls overwrite the storage of older calls. - * Note: this is not used in any of the logging functions, so their - * callers may use it. - */ -extern const char *ip_str(const ip_address *src); - -/* - * call this routine to reset daily items. - */ -extern void daily_log_reset(void); -extern void daily_log_event(void); - -/* - * some events are to be logged only occasionally. - */ -extern bool logged_txt_warning; -extern bool logged_myid_ip_txt_warning; -extern bool logged_myid_ip_key_warning; -extern bool logged_myid_fqdn_txt_warning; -extern bool logged_myid_fqdn_key_warning; diff --git a/src/pluto/modecfg.c b/src/pluto/modecfg.c deleted file mode 100644 index 8298ea601..000000000 --- a/src/pluto/modecfg.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* Mode config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc. - * Copyright (C) 2003-2004 Xelerance Corporation - * Copyright (C) 2006-2010 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * This code originally written by Colubris Networks, Inc. - * Extraction of patch and porting to 1.99 codebases by Xelerance Corporation - * Porting to 2.x by Sean Mathews - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "state.h" -#include "demux.h" -#include "timer.h" -#include "ipsec_doi.h" -#include "log.h" -#include "crypto.h" -#include "modecfg.h" -#include "whack.h" -#include "pluto.h" - -#define MAX_XAUTH_TRIES 3 - -#define DEFAULT_UNITY_BANNER "Welcome to strongSwan - the Linux VPN Solution!\n" - -/** - * Creates a modecfg_attribute_t object - */ -static modecfg_attribute_t *modecfg_attribute_create(configuration_attribute_type_t type, - chunk_t value) -{ - modecfg_attribute_t *this; - - this = malloc_thing(modecfg_attribute_t); - this->type = ((u_int16_t)type) & 0x7FFF; - this->is_tv = FALSE; - this->value = chunk_clone(value); - this->handler = NULL; - - return this; -} - -/** - * Creates a modecfg_attribute_t object coded in TV format - */ -static modecfg_attribute_t *modecfg_attribute_create_tv(configuration_attribute_type_t type, - size_t value) -{ - modecfg_attribute_t *this; - - this = modecfg_attribute_create(type, chunk_empty); - this->value.len = value; - this->is_tv = TRUE; - - return this; -} - -/** - * Destroys a modecfg_attribute_t object - */ -void modecfg_attribute_destroy(modecfg_attribute_t *this) -{ - free(this->value.ptr); - free(this); -} - -/** - * Get attributes to be sent to client - */ -static void get_attributes(connection_t *c, linked_list_t *ca_list) -{ - configuration_attribute_type_t type; - identification_t *client_id; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - chunk_t value; - host_t *vip = NULL, *requested_vip = NULL; - bool want_unity_banner = FALSE; - int family; - -#ifdef CISCO_QUIRKS - /* always send banner in ModeCfg push mode */ - if (ca_list->get_count(ca_list) == 0) - { - want_unity_banner = TRUE; - } -#endif - - /* scan list of requested attributes in ModeCfg pull mode */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP6_ADDRESS: - { - int family; - - family = (ca->type == INTERNAL_IP4_ADDRESS) ? AF_INET : AF_INET6; - DESTROY_IF(requested_vip); - requested_vip = (ca->value.len) ? - host_create_from_chunk(family, ca->value, 0) : - host_create_any(family); - plog("peer requested virtual IP %H", requested_vip); - break; - } -#ifdef CISCO_QUIRKS - case UNITY_BANNER: - want_unity_banner = TRUE; - break; -#endif - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (requested_vip == NULL) - { - requested_vip = host_create_any(AF_INET); - } - - client_id = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - /* if no virtual IP has been assigned yet - acquire one */ - if (c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - if (c->spd.that.pool) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - c->spd.that.pool, client_id, requested_vip); - if (vip) - { - c->spd.that.host_srcip->destroy(c->spd.that.host_srcip); - c->spd.that.host_srcip = vip; - } - } - else - { - plog("no virtual IP found"); - } - } - - requested_vip->destroy(requested_vip); - - /* if we have a virtual IP address - send it */ - if (!c->spd.that.host_srcip->is_anyaddr(c->spd.that.host_srcip)) - { - vip = c->spd.that.host_srcip; - plog("assigning virtual IP %H to peer", vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : - INTERNAL_IP6_ADDRESS, - vip->get_address(vip)); - ca_list->insert_last(ca_list, ca); - - /* set the remote client subnet to virtual IP */ - c->spd.that.client.addr = *(ip_address*)vip->get_sockaddr(vip); - c->spd.that.client.maskbits = (family == AF_INET) ? 32 : 128; - c->spd.that.has_client = TRUE; - } - - /* assign attributes from registered providers */ - enumerator = hydra->attributes->create_responder_enumerator(hydra->attributes, - c->spd.that.pool, client_id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca_list->insert_last(ca_list, ca); - if (type == UNITY_BANNER) - { - want_unity_banner = FALSE; - } - } - enumerator->destroy(enumerator); - - if (want_unity_banner) - { - ca = modecfg_attribute_create(UNITY_BANNER, - chunk_create(DEFAULT_UNITY_BANNER, - strlen(DEFAULT_UNITY_BANNER))); - ca_list->insert_last(ca_list, ca); - } -} - -/** - * Set srcip and client subnet to internal IP address - */ -static bool set_attributes(connection_t *c, linked_list_t *ca_list) -{ - host_t *vip, *srcip; - modecfg_attribute_t *ca, *ca_handler; - enumerator_t *enumerator; - bool vip_set = FALSE; - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - int family = AF_INET6; - attribute_handler_t *handler = NULL; - enumerator_t *e; - - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_ADDRESS: - if (ca->value.len == 0) - { - vip = host_create_any(family); - } - else - { - /* skip prefix byte in IPv6 payload*/ - if (family == AF_INET6) - { - ca->value.len = 16; - } - vip = host_create_from_chunk(family, ca->value, 0); - } - if (vip) - { - srcip = c->spd.this.host_srcip; - - if (srcip->is_anyaddr(srcip) || srcip->equals(srcip, vip)) - { - plog("setting virtual IP source address to %H", vip); - } - else - { - plog("replacing virtual IP source address %H by %H", - srcip, vip); - } - srcip->destroy(srcip); - c->spd.this.host_srcip = vip; - - /* setting client subnet to vip/32 */ - addrtosubnet((ip_address*)vip->get_sockaddr(vip), - &c->spd.this.client); - setportof(0, &c->spd.this.client.addr); - c->spd.this.has_client = TRUE; - - vip_set = TRUE; - } - continue; - case APPLICATION_VERSION: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - if (ca->value.len > 0) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - - /* find the first handler which requested this attribute */ - e = c->requested->create_enumerator(c->requested); - while (e->enumerate(e, &ca_handler)) - { - if (ca_handler->type == ca->type) - { - handler = ca_handler->handler; - break; - } - } - e->destroy(e); - - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - c->spd.that.id, handler, ca->type, ca->value); - if (handler) - { - ca_handler = modecfg_attribute_create(ca->type, ca->value); - ca_handler->handler = handler; - - if (c->attributes == NULL) - { - c->attributes = linked_list_create(); - } - c->attributes->insert_last(c->attributes, ca_handler); - } - } - enumerator->destroy(enumerator); - c->requested->destroy_function(c->requested, (void*)modecfg_attribute_destroy); - c->requested = NULL; - return vip_set; -} - -/** - * Register configuration attribute handlers - */ -static void register_attribute_handlers(connection_t *c) -{ - configuration_attribute_type_t type; - modecfg_attribute_t *ca; - chunk_t value; - attribute_handler_t *handler; - enumerator_t *enumerator; - - /* add configuration attributes requested by handlers */ - if (c->requested == NULL) - { - c->requested = linked_list_create(); - } - enumerator = hydra->attributes->create_initiator_enumerator( - hydra->attributes,c->spd.that.id, c->spd.this.host_srcip); - while (enumerator->enumerate(enumerator, &handler, &type, &value)) - { - ca = modecfg_attribute_create(type, value); - ca->handler = handler; - c->requested->insert_last(c->requested, ca); - } - enumerator->destroy(enumerator); -} - -/** - * Compute HASH of Mode Config. - */ -static size_t modecfg_hash(u_char *dest, u_char *start, u_char *roof, - const struct state *st) -{ - chunk_t msgid_chunk = chunk_from_thing(st->st_msgid); - chunk_t msg_chunk = { start, roof - start }; - size_t prf_block_size; - pseudo_random_function_t prf_alg; - prf_t *prf; - - prf_alg = oakley_to_prf(st->st_oakley.hash); - prf = lib->crypto->create_prf(lib->crypto, prf_alg); - prf->set_key(prf, st->st_skeyid_a); - prf->get_bytes(prf, msgid_chunk, NULL); - prf->get_bytes(prf, msg_chunk, dest); - prf_block_size = prf->get_block_size(prf); - prf->destroy(prf); - - DBG(DBG_CRYPT, - DBG_log("ModeCfg HASH computed:"); - DBG_dump("", dest, prf_block_size) - ) - return prf_block_size; -} - - -/** - * Generate an IKE message containing ModeCfg information (eg: IP, DNS, WINS) - */ -static stf_status modecfg_build_msg(struct state *st, pb_stream *rbody, - u_int16_t msg_type, linked_list_t *ca_list, - u_int16_t ap_id) -{ - u_char *r_hash_start, *r_hashval; - struct isakmp_mode_attr attrh; - struct isakmp_attribute attr; - pb_stream strattr,attrval; - enumerator_t *enumerator; - modecfg_attribute_t *ca; - - START_HASH_PAYLOAD(*rbody, ISAKMP_NEXT_ATTR); - - attrh.isama_np = ISAKMP_NEXT_NONE; - attrh.isama_type = msg_type; - attrh.isama_identifier = ap_id; - - if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr)) - { - return STF_INTERNAL_ERROR; - } - - enumerator = ca_list->create_enumerator(ca_list); - while (enumerator->enumerate(enumerator, &ca)) - { - DBG(DBG_CONTROLMORE, - DBG_log("building %N attribute", configuration_attribute_type_names, ca->type) - ) - if (ca->is_tv) - { - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TV; - attr.isaat_lv = ca->value.len; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - } - else - { - char buf[BUF_LEN]; - - attr.isaat_af_type = ca->type | ISAKMP_ATTR_AF_TLV; - out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval); - snprintf(buf, BUF_LEN, "%N", configuration_attribute_type_names, ca->type); - out_raw(ca->value.ptr, ca->value.len, &attrval, buf); - } - close_output_pbs(&attrval); - } - enumerator->destroy(enumerator); - close_output_pbs(&strattr); - - modecfg_hash(r_hashval, r_hash_start, rbody->cur, st); - close_message(rbody); - encrypt_message(rbody, st); - return STF_OK; -} - -/** - * Send ModeCfg message - */ -static stf_status modecfg_send_msg(struct state *st, int isama_type, - linked_list_t *ca_list) -{ - pb_stream msg; - pb_stream rbody; - char buf[BUF_LEN]; - - /* set up attr */ - init_pbs(&msg, buf, sizeof(buf), "ModeCfg msg buffer"); - - /* this is the beginning of a new exchange */ - st->st_msgid = generate_msgid(st); - init_phase2_iv(st, &st->st_msgid); - - /* HDR out */ - { - struct isakmp_hdr hdr; - - zero(&hdr); /* default to 0 */ - hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION; - hdr.isa_np = ISAKMP_NEXT_HASH; - hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG; - hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION; - memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE); - memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE); - hdr.isa_msgid = st->st_msgid; - - if (!out_struct(&hdr, &isakmp_hdr_desc, &msg, &rbody)) - { - return STF_INTERNAL_ERROR; - } - } - - /* ATTR out with isama_id of 0 */ - modecfg_build_msg(st, &rbody, isama_type, ca_list, 0); - - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(msg.start, pbs_offset(&msg)); - st->st_tpacket = chunk_clone(st->st_tpacket); - - /* Transmit */ - send_packet(st, "ModeCfg msg"); - - if (st->st_event->ev_type != EVENT_RETRANSMIT) - { - delete_event(st); - event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st); - } - return STF_OK; -} - -/** - * Parse a ModeCfg attribute payload - */ -static stf_status modecfg_parse_attributes(pb_stream *attrs, linked_list_t *ca_list) -{ - struct isakmp_attribute attr; - pb_stream strattr; - u_int16_t attr_type; - u_int16_t attr_len; - chunk_t attr_chunk; - modecfg_attribute_t *ca; - - while (pbs_left(attrs) >= sizeof(struct isakmp_attribute)) - { - if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr)) - { - return STF_FAIL; - } - attr_type = attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK; - attr_len = attr.isaat_lv; - DBG(DBG_CONTROLMORE, - DBG_log("processing %N attribute", - configuration_attribute_type_names, attr_type) - ) - - switch (attr_type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (attr_len != 4 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP4_SUBNET: - if (attr_len != 8 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_NETMASK: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_ADDRESS: - if (attr_len != 17 && attr_len != 16 && attr_len != 0) - { - goto error; - } - break; - case INTERNAL_IP6_SUBNET: - if (attr_len != 17 && attr_len != 0) - { - goto error; - } - break; - case SUPPORTED_ATTRIBUTES: - if (attr_len % 2) - { - goto error; - } - break; - case APPLICATION_VERSION: - break; - /* XAUTH attributes */ - case XAUTH_TYPE: - case XAUTH_STATUS: - case XAUTH_USER_NAME: - case XAUTH_USER_PASSWORD: - case XAUTH_PASSCODE: - case XAUTH_MESSAGE: - case XAUTH_CHALLENGE: - case XAUTH_DOMAIN: - case XAUTH_NEXT_PIN: - case XAUTH_ANSWER: - break; - /* Microsoft attributes */ - case INTERNAL_IP4_SERVER: - case INTERNAL_IP6_SERVER: - break; - /* Cisco Unity attributes */ - case UNITY_BANNER: - case UNITY_SAVE_PASSWD: - case UNITY_DEF_DOMAIN: - case UNITY_SPLITDNS_NAME: - case UNITY_SPLIT_INCLUDE: - case UNITY_NATT_PORT: - case UNITY_LOCAL_LAN: - case UNITY_PFS: - case UNITY_FW_TYPE: - case UNITY_BACKUP_SERVERS: - case UNITY_DDNS_HOSTNAME: - break; - default: - plog("unknown attribute type (%u)", attr_type); - continue; - } - - /* add attribute */ - if (attr.isaat_af_type & ISAKMP_ATTR_AF_TV) - { - ca = modecfg_attribute_create_tv(attr_type, attr_len); - } - else - { - attr_chunk = chunk_create(strattr.cur, attr_len); - ca = modecfg_attribute_create(attr_type, attr_chunk); - } - ca_list->insert_last(ca_list, ca); - } - return STF_OK; - -error: - plog("%N attribute has invalid size of %u octets", - configuration_attribute_type_names, attr_type, attr_len); - return STF_FAIL; -} - -/** - * Parse a ModeCfg message - */ -static stf_status modecfg_parse_msg(struct msg_digest *md, int isama_type, - u_int16_t *isama_id, linked_list_t *ca_list) -{ - modecfg_attribute_t *ca; - struct state *const st = md->st; - struct payload_digest *p; - stf_status stat; - - st->st_msgid = md->hdr.isa_msgid; - - CHECK_QUICK_HASH(md, modecfg_hash(hash_val, hash_pbs->roof, - md->message_pbs.roof, st), "MODECFG-HASH", "ISAKMP_CFG_MSG"); - - /* process the ModeCfg payloads received */ - for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next) - { - if (p->payload.attribute.isama_type == isama_type) - { - *isama_id = p->payload.attribute.isama_identifier; - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - if (stat == STF_OK) - { - /* return with a valid set of attributes */ - return STF_OK; - } - } - else - { - plog("expected %s, got %s instead (ignored)" - , enum_name(&attr_msg_type_names, isama_type) - , enum_name(&attr_msg_type_names, p->payload.attribute.isama_type)); - - stat = modecfg_parse_attributes(&p->pbs, ca_list); - } - - /* abort if a parsing error occurred */ - if (stat != STF_OK) - { - ca_list->destroy_function(ca_list, (void*)modecfg_attribute_destroy); - return stat; - } - - /* discard the parsed attributes and look for another payload */ - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) {} - } - return STF_IGNORE; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c - * client -> CFG_REQUEST - * STF_OK transitions to STATE_MODE_CFG_I1 - */ -stf_status modecfg_send_request(struct state *st) -{ - connection_t *c = st->st_connection; - stf_status stat; - modecfg_attribute_t *ca; - enumerator_t *enumerator; - int family; - chunk_t value; - host_t *vip; - linked_list_t *ca_list = linked_list_create(); - - vip = c->spd.this.host_srcip; - value = vip->is_anyaddr(vip) ? chunk_empty : vip->get_address(vip); - family = vip->get_family(vip); - ca = modecfg_attribute_create((family == AF_INET) ? - INTERNAL_IP4_ADDRESS : INTERNAL_IP6_ADDRESS, - value); - ca_list->insert_last(ca_list, ca); - - register_attribute_handlers(c); - enumerator = c->requested->create_enumerator(c->requested); - while (enumerator->enumerate(enumerator, &ca)) - { - ca = modecfg_attribute_create(ca->type, chunk_empty); - ca_list->insert_last(ca_list, ca); - } - enumerator->destroy(enumerator); - - plog("sending ModeCfg request"); - - st->st_state = STATE_MODE_CFG_I1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg pull mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R0 - * server <- CFG_REQUEST - * server -> CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_R0 - */ -stf_status modecfg_inR0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* build the CFG_REPLY */ - get_attributes(st->st_connection, ca_list); - - plog("sending ModeCfg reply"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg pull mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I1 - * client <- CFG_REPLY - * STF_OK transitions to STATE_MODE_CFG_I2 - */ -stf_status modecfg_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - st->st_msgid = 0; - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c - * server -> CFG_SET - * STF_OK transitions to STATE_MODE_CFG_R3 - */ -stf_status modecfg_send_set(struct state *st) -{ - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - - plog("sending ModeCfg set"); - - get_attributes(st->st_connection, ca_list); - st->st_state = STATE_MODE_CFG_R3; - stat = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_modecfg.started = TRUE; - } - return stat; -} - -/** - * Used in ModeCfg push mode on the client (initiator) - * called in demux.c from STATE_MODE_CFG_I0 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_I3 - */ -stf_status modecfg_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list, *ca_ack_list; - - plog("parsing ModeCfg set"); - - ca_list = linked_list_create(); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - register_attribute_handlers(st->st_connection); - st->st_modecfg.vars_set = set_attributes(st->st_connection, ca_list); - - /* prepare ModeCfg ack which sends zero length attributes */ - ca_ack_list = linked_list_create(); - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case APPLICATION_VERSION: - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: -#ifdef CISCO_QUIRKS - case UNITY_BANNER: -#endif - /* supported attributes */ - ca->value.len = 0; - ca_ack_list->insert_last(ca_ack_list, ca); - break; - default: - /* unsupportd attributes */ - modecfg_attribute_destroy(ca); - } - } - ca_list->destroy(ca_list); - - plog("sending ModeCfg ack"); - - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, - ca_ack_list, isama_id); - ca_ack_list->destroy_function(ca_ack_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used in ModeCfg push mode on the server (responder) - * called in demux.c from STATE_MODE_CFG_R3 - * server <- CFG_ACK - * STF_OK transitions to STATE_MODE_CFG_R4 - */ -stf_status modecfg_inR3(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing ModeCfg ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat != STF_OK) - { - return stat; - } - st->st_msgid = 0; - return STF_OK; -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c - * server -> CFG_REQUEST - * STF_OK transitions to STATE_XAUTH_R1 - */ -stf_status xauth_send_request(struct state *st) -{ - stf_status stat; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - ca = modecfg_attribute_create(XAUTH_USER_NAME, chunk_empty); - ca_list->insert_last(ca_list, ca); - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, chunk_empty); - ca_list->insert_last(ca_list, ca); - - plog("sending XAUTH request"); - st->st_state = STATE_XAUTH_R1; - stat = modecfg_send_msg(st, ISAKMP_CFG_REQUEST, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - } - return stat; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I0 - * client <- CFG_REQUEST - * client -> CFG_REPLY - * STF_OK transitions to STATE_XAUTH_I1 - */ -stf_status xauth_inI0(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - bool xauth_user_name_present = FALSE; - bool xauth_user_password_present = FALSE; - bool xauth_type_present = FALSE; - chunk_t xauth_user_name, xauth_user_password; - identification_t *user_id; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH request"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REQUEST, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_TYPE: - if (ca->value.len != XAUTH_TYPE_GENERIC) - { - plog("xauth type %s is not supported", - enum_name(&xauth_type_names, ca->value.len)); - stat = STF_FAIL; - } - else - { - xauth_type_present = TRUE; - } - break; - case XAUTH_USER_NAME: - xauth_user_name_present = TRUE; - break; - case XAUTH_USER_PASSWORD: - xauth_user_password_present = TRUE; - break; - case XAUTH_MESSAGE: - if (ca->value.len) - { - DBG(DBG_PARSING | DBG_CONTROLMORE, - DBG_log(" '%.*s'", ca->value.len, ca->value.ptr) - ) - } - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - - if (!xauth_user_name_present) - { - plog("user name attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - if (!xauth_user_password_present) - { - plog("user password attribute is missing in XAUTH request"); - stat = STF_FAIL; - } - - /* prepare XAUTH reply */ - if (stat == STF_OK) - { - /* get user credentials using a plugin function */ - if (!pluto->xauth->get_secret(pluto->xauth, c, &xauth_user_password)) - { - plog("xauth user credentials not found"); - stat = STF_FAIL; - } - } - if (stat == STF_OK) - { - /* insert xauth type if present */ - if (xauth_type_present) - { - ca = modecfg_attribute_create_tv(XAUTH_TYPE, XAUTH_TYPE_GENERIC); - ca_list->insert_last(ca_list, ca); - } - - /* insert xauth user name */ - user_id = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - xauth_user_name = user_id->get_encoding(user_id); - DBG(DBG_CONTROL, - DBG_log("my xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_NAME, xauth_user_name); - ca_list->insert_last(ca_list, ca); - - /* insert xauth user password */ - DBG(DBG_PRIVATE, - DBG_log("my xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - ca = modecfg_attribute_create(XAUTH_USER_PASSWORD, xauth_user_password); - ca_list->insert_last(ca_list, ca); - chunk_clear(&xauth_user_password); - } - else - { - ca = modecfg_attribute_create_tv(XAUTH_STATUS, XAUTH_STATUS_FAIL); - ca_list->insert_last(ca_list, ca); - } - - plog("sending XAUTH reply"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_REPLY, - ca_list, isama_id); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - if (stat == STF_OK) - { - st->st_xauth.started = TRUE; - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH reply msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH reply msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R1 - server <- CFG_REPLY - server -> CFG_SET - STF_OK transitions to STATE_XAUTH_R2 - */ -stf_status xauth_inR1(struct msg_digest *md) -{ - struct state *const st = md->st; - connection_t *c = st->st_connection; - u_int16_t isama_id; - stf_status stat, stat_build; - chunk_t xauth_user_name, xauth_user_password; - int xauth_status = XAUTH_STATUS_OK; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH reply"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_REPLY, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - - /* initialize xauth_secret */ - xauth_user_name = chunk_empty; - xauth_user_password = chunk_empty; - - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - switch (ca->type) - { - case XAUTH_STATUS: - xauth_status = ca->value.len; - break; - case XAUTH_USER_NAME: - xauth_user_name = chunk_clone(ca->value); - break; - case XAUTH_USER_PASSWORD: - xauth_user_password = chunk_clone(ca->value); - break; - default: - break; - } - modecfg_attribute_destroy(ca); - } - /* did the client return an XAUTH FAIL status? */ - if (xauth_status == XAUTH_STATUS_FAIL) - { - plog("received FAIL status in XAUTH reply"); - - /* client is not able to do XAUTH, delete ISAKMP SA */ - free(xauth_user_name.ptr); - free(xauth_user_password.ptr); - delete_state(st); - ca_list->destroy(ca_list); - return STF_IGNORE; - } - - /* check XAUTH reply */ - if (xauth_user_name.ptr == NULL) - { - plog("user name attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else if (xauth_user_password.ptr == NULL) - { - plog("user password attribute is missing in XAUTH reply"); - st->st_xauth.status = FALSE; - } - else - { - DBG(DBG_CONTROL, - DBG_log("peer xauth user name is '%.*s'", xauth_user_name.len, - xauth_user_name.ptr) - ) - DESTROY_IF(c->xauth_identity); - c->xauth_identity = identification_create_from_data(xauth_user_name); - - DBG(DBG_PRIVATE, - DBG_log("peer xauth user password is '%.*s'", xauth_user_password.len, - xauth_user_password.ptr) - ) - /* verify the user credentials using a plugin function */ - st->st_xauth.status = pluto->xauth->verify_secret(pluto->xauth, c, - xauth_user_password); - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - } - chunk_clear(&xauth_user_name); - chunk_clear(&xauth_user_password); - - plog("sending XAUTH status"); - xauth_status = (st->st_xauth.status) ? XAUTH_STATUS_OK : XAUTH_STATUS_FAIL; - ca = modecfg_attribute_create_tv(XAUTH_STATUS, xauth_status); - ca_list->insert_last(ca_list, ca); - stat_build = modecfg_send_msg(st, ISAKMP_CFG_SET, ca_list); - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - if (stat_build != STF_OK) - { - return stat_build; - } - return STF_OK; -} - -/** - * Used on the XAUTH client (initiator) - * called in demux.c from STATE_XAUTH_I1 - * client <- CFG_SET - * client -> CFG_ACK - * STF_OK transitions to STATE_XAUTH_I2 - */ -stf_status xauth_inI1(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat, stat_build; - modecfg_attribute_t *ca; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH status"); - stat = modecfg_parse_msg(md, ISAKMP_CFG_SET, &isama_id, ca_list); - if (stat != STF_OK) - { - /* notification payload - not exactly the right choice, but okay */ - md->note = ISAKMP_ATTRIBUTES_NOT_SUPPORTED; - return stat; - } - - st->st_xauth.status = FALSE; - while (ca_list->remove_last(ca_list, (void **)&ca) == SUCCESS) - { - if (ca->type == XAUTH_STATUS) - { - st->st_xauth.status = (ca->value.len == XAUTH_STATUS_OK); - } - modecfg_attribute_destroy(ca); - } - plog("extended authentication %s", st->st_xauth.status? "was successful":"failed"); - - plog("sending XAUTH ack"); - stat_build = modecfg_build_msg(st, &md->rbody, ISAKMP_CFG_ACK, ca_list, isama_id); - ca_list->destroy(ca_list); - - if (stat_build != STF_OK) - { - return stat_build; - } - if (st->st_xauth.status) - { - st->st_msgid = 0; - return STF_OK; - } - else - { - /* send XAUTH ack msg and then delete ISAKMP SA */ - free(st->st_tpacket.ptr); - st->st_tpacket = chunk_create(md->reply.start, pbs_offset(&md->reply)); - st->st_tpacket = chunk_clone(st->st_tpacket); - send_packet(st, "XAUTH ack msg"); - delete_state(st); - return STF_IGNORE; - } -} - -/** - * Used on the XAUTH server (responder) - * called in demux.c from STATE_XAUTH_R2 - * server <- CFG_ACK - * STF_OK transitions to STATE_XAUTH_R3 - */ -stf_status xauth_inR2(struct msg_digest *md) -{ - struct state *const st = md->st; - u_int16_t isama_id; - stf_status stat; - linked_list_t *ca_list = linked_list_create(); - - plog("parsing XAUTH ack"); - - stat = modecfg_parse_msg(md, ISAKMP_CFG_ACK, &isama_id, ca_list); - if (stat != STF_OK) - { - return stat; - } - ca_list->destroy_function(ca_list, (void *)modecfg_attribute_destroy); - st->st_msgid = 0; - if (st->st_xauth.status) - { - return STF_OK; - } - else - { - delete_state(st); - return STF_IGNORE; - } - -} diff --git a/src/pluto/modecfg.h b/src/pluto/modecfg.h deleted file mode 100644 index 7adf18682..000000000 --- a/src/pluto/modecfg.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Mode Config related functions - * Copyright (C) 2001-2002 Colubris Networks - * Copyright (C) 2003-2004 Xelerance Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MODECFG_H -#define _MODECFG_H - -#include -#include - -#include "state.h" -#include "demux.h" - -typedef struct modecfg_attribute_t modecfg_attribute_t; - -/** - * Defines a modecfg_attribute_t object. - */ -struct modecfg_attribute_t { - /** - * Type of the attribute. - */ - u_int16_t type; - - /** - * Attribute is coded as TV - */ - bool is_tv; - - /** - * Attribute value as chunk. - */ - chunk_t value; - - /** - * Attribute handler. - */ - attribute_handler_t *handler; -}; - -/* Destroys a modecfg_attribute_t object */ -extern void modecfg_attribute_destroy(modecfg_attribute_t *this); - -/* ModeConfig pull mode start function */ -extern stf_status modecfg_send_request(struct state *st); - -/* ModeConfig pull mode state transition functions */ -extern stf_status modecfg_inR0(struct msg_digest *md); -extern stf_status modecfg_inI1(struct msg_digest *md); - -/* ModeConfig push mode start function */ -extern stf_status modecfg_send_set(struct state *st); - -/* ModeConfig push mode state transition functions */ -extern stf_status modecfg_inI0(struct msg_digest *md); -extern stf_status modecfg_inR3(struct msg_digest *md); - -/* XAUTH start function */ -extern stf_status xauth_send_request(struct state *st); - -/* XAUTH state transition funcgtions */ -extern stf_status xauth_inI0(struct msg_digest *md); -extern stf_status xauth_inR1(struct msg_digest *md); -extern stf_status xauth_inI1(struct msg_digest *md); -extern stf_status xauth_inR2(struct msg_digest *md); - -#endif /* _MODECFG_H */ diff --git a/src/pluto/myid.c b/src/pluto/myid.c deleted file mode 100644 index c90d14ef8..000000000 --- a/src/pluto/myid.c +++ /dev/null @@ -1,121 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says defines this */ -# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */ -#endif - -#include - -#include - -#include "myid.h" -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "connections.h" -#include "packet.h" -#include "whack.h" - -enum myid_state myid_state = MYID_UNKNOWN; - -identification_t *myids[MYID_SPECIFIED+1]; /* %myid */ - -/** - * Fills in myid from environment variable IPSECmyid or defaultrouteaddr - */ -void init_myid(void) -{ - myid_state = MYID_UNKNOWN; - { - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - myids[s] = identification_create_from_string("%any"); - } - } - set_myid(MYID_SPECIFIED, getenv("IPSECmyid")); - set_myid(MYID_IP, getenv("defaultrouteaddr")); - set_myFQDN(); -} - -/** - * Free myid module - */ -void free_myid(void) -{ - enum myid_state s; - - for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++) - { - DESTROY_IF(myids[s]); - } -} - -void set_myid(enum myid_state s, char *idstr) -{ - if (idstr) - { - myids[s]->destroy(myids[s]); - myids[s] = identification_create_from_string(idstr); - if (s == MYID_SPECIFIED) - { - myid_state = MYID_SPECIFIED; - } - } -} - -void set_myFQDN(void) -{ - char FQDN[HOST_NAME_MAX + 1]; - int r = gethostname(FQDN, sizeof(FQDN)); - size_t len; - - if (r != 0) - { - log_errno((e, "gethostname() failed in set_myFQDN")); - } - else - { - FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */ - len = strlen(FQDN); - - if (len > 0 && FQDN[len-1] == '.') - { - /* nuke trailing . */ - FQDN[len-1] = '\0'; - } - if (!strcaseeq(FQDN, "localhost.localdomain")) - { - myids[MYID_HOSTNAME]->destroy(myids[MYID_HOSTNAME]); - myids[MYID_HOSTNAME] = identification_create_from_string(FQDN); - } - } -} - -void show_myid_status(void) -{ - whack_log(RC_COMMENT, "%%myid = '%Y'", myids[myid_state]); -} - -/* - * Local Variables: - * c-basic-offset:4 - * c-style: pluto - * End: - */ diff --git a/src/pluto/myid.h b/src/pluto/myid.h deleted file mode 100644 index 012a34968..000000000 --- a/src/pluto/myid.h +++ /dev/null @@ -1,38 +0,0 @@ -/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1) - * Copyright (C) 1999-2001 D. Hugh Redelmeier - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _MYID_H -#define _MYID_H - -#include - -extern void init_myid(void); -extern void free_myid(void); - -enum myid_state { - MYID_UNKNOWN, /* not yet figured out */ - MYID_HOSTNAME, /* our current hostname */ - MYID_IP, /* our default IP address */ - MYID_SPECIFIED /* as specified by ipsec.conf */ -}; - -extern enum myid_state myid_state; -extern identification_t* myids[MYID_SPECIFIED+1]; /* %myid */ -extern void set_myid(enum myid_state s, char *); -extern void show_myid_status(void); -extern void set_myFQDN(void); - -#define resolve_myid(id) ((id)->get_type(id) == ID_MYID? myids[myid_state] : (id)) - -#endif /* _MYID_H */ diff --git a/src/pluto/nat_traversal.c b/src/pluto/nat_traversal.c deleted file mode 100644 index 28be76825..000000000 --- a/src/pluto/nat_traversal.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Copyright (C) 2009 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2005 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* used only if MSG_NOSIGNAL not defined */ -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "server.h" -#include "state.h" -#include "connections.h" -#include "packet.h" -#include "demux.h" -#include "kernel.h" -#include "whack.h" -#include "timer.h" -#include "cookie.h" -#include "crypto.h" -#include "vendor.h" -#include "ike_alg.h" -#include "nat_traversal.h" - -/* #define FORCE_NAT_TRAVERSAL */ -#define NAT_D_DEBUG -#define NAT_T_SUPPORT_LAST_DRAFTS - -#ifndef SOL_UDP -#define SOL_UDP 17 -#endif - -#ifndef UDP_ESPINUDP -#define UDP_ESPINUDP 100 -#endif - -#define DEFAULT_KEEP_ALIVE_PERIOD 20 - -#ifdef _IKE_ALG_H -/* Alg patch: hash_digest_len -> hash_digest_size */ -#define hash_digest_len hash_digest_size -#endif - -bool nat_traversal_enabled = FALSE; -bool nat_traversal_support_non_ike = FALSE; -bool nat_traversal_support_port_floating = FALSE; - -static unsigned int _kap = 0; -static unsigned int _ka_evt = 0; -static bool _force_ka = 0; - -static const char *natt_version = "0.6c"; - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf) -{ - nat_traversal_enabled = activate; - nat_traversal_support_non_ike = activate; -#ifdef NAT_T_SUPPORT_LAST_DRAFTS - nat_traversal_support_port_floating = activate ? spf : FALSE; -#endif - _force_ka = fka; - _kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD; - plog(" including NAT-Traversal patch (Version %s)%s%s%s" - , natt_version, activate ? "" : " [disabled]" - , activate & fka ? " [Force KeepAlive]" : "" - , activate & !spf ? " [Port Floating disabled]" : ""); -} - -static void disable_nat_traversal (int type) -{ - if (type == ESPINUDP_WITH_NON_IKE) - nat_traversal_support_non_ike = FALSE; - else - nat_traversal_support_port_floating = FALSE; - - if (!nat_traversal_support_non_ike && - !nat_traversal_support_port_floating) - nat_traversal_enabled = FALSE; -} - -static void _natd_hash(const struct hash_desc *oakley_hasher, char *hash, - u_int8_t *icookie, u_int8_t *rcookie, - const ip_address *ip, u_int16_t port) -{ - if (is_zero_cookie(icookie)) - { - DBG_log("_natd_hash: Warning, icookie is zero !!"); - } - if (is_zero_cookie(rcookie)) - { - DBG_log("_natd_hash: Warning, rcookie is zero !!"); - } - - /** - * draft-ietf-ipsec-nat-t-ike-01.txt - * - * HASH = HASH(CKY-I | CKY-R | IP | Port) - * - * All values in network order - */ - { - chunk_t icookie_chunk = { icookie, COOKIE_SIZE }; - chunk_t rcookie_chunk = { rcookie, COOKIE_SIZE }; - chunk_t port_chunk = chunk_from_thing(port); - chunk_t addr_chunk; - hash_algorithm_t hash_alg; - hasher_t *hasher; - size_t hash_size; - - hash_alg = oakley_to_hash_algorithm(oakley_hasher->algo_id); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->get_hash(hasher, icookie_chunk, NULL); - hasher->get_hash(hasher, rcookie_chunk, NULL); - switch (addrtypeof(ip)) - { - case AF_INET: - addr_chunk = chunk_from_thing(ip->u.v4.sin_addr.s_addr); - break; - case AF_INET6: - addr_chunk = chunk_from_thing(ip->u.v6.sin6_addr.s6_addr); - break; - default: - addr_chunk = chunk_empty; /* should never occur */ - } - hasher->get_hash(hasher, addr_chunk, NULL); - hasher->get_hash(hasher, port_chunk, hash); - hash_size = hasher->get_hash_size(hasher); - hasher->destroy(hasher); -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_dump_chunk("_natd_hash: icookie=", icookie_chunk); - DBG_dump_chunk("_natd_hash: rcookie=", rcookie_chunk); - DBG_dump_chunk("_natd_hash: ip=", addr_chunk); - DBG_log("_natd_hash: port=%d", port); - DBG_dump("_natd_hash: hash=", hash, hash_size); - ) -#endif - } -} - -/* Add NAT-Traversal VIDs (supported ones) - * used when we are Initiator - */ -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs) -{ - bool r = TRUE; - - if (nat_traversal_support_port_floating) - { - u_int8_t last_np = nat_traversal_support_non_ike ? - ISAKMP_NEXT_VID : np; - - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03); - if (r) - r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_02); - if (r) - r = out_vendorid(last_np, outs, VID_NATT_IETF_02_N); - } - if (nat_traversal_support_non_ike) - { - if (r) - r = out_vendorid(np, outs, VID_NATT_IETF_00); - } - return r; -} - -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid) -{ - switch (nat_t_vid) - { - case VID_NATT_IETF_00: - return LELEM(NAT_TRAVERSAL_IETF_00_01); - case VID_NATT_IETF_02: - case VID_NATT_IETF_02_N: - case VID_NATT_IETF_03: - return LELEM(NAT_TRAVERSAL_IETF_02_03); - case VID_NATT_RFC: - return LELEM(NAT_TRAVERSAL_RFC); - } - return 0; -} - -void nat_traversal_natd_lookup(struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct payload_digest *p; - struct state *st = md->st; - int i; - - if (!st || !md->iface || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /** Count NAT-D **/ - for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++); - - /* - * We need at least 2 NAT-D (1 for us, many for peer) - */ - if (i < 2) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negotiation", i); - st->nat_traversal = 0; - return; - } - - /* - * First one with my IP & port - */ - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->iface->addr), ntohs(st->st_connection->spd.this.host_port)); - - if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len))) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_ME"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); - } - - /* - * The others with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, - &(md->sender), ntohs(md->sender_port)); - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len && - memeq(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)) - { - i++; - } - } - if (!i) - { -#ifdef NAT_D_DEBUG - DBG(DBG_NATT, - DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER"); - DBG_dump("expected NAT-D:", hash - , st->st_oakley.hasher->hash_digest_len); - p = md->chain[ISAKMP_NEXT_NATD_RFC]; - for (p = p->next, i=0 ; p != NULL; p = p->next) - { - DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); - } - ) -#endif - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - } -#ifdef FORCE_NAT_TRAVERSAL - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); - st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); -#endif -} - -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md) -{ - char hash[MAX_DIGEST_LEN]; - struct state *st = md->st; - - if (!st || !st->st_oakley.hasher) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - - DBG(DBG_EMITTING, - DBG_log("sending NATD payloads") - ) - - /* - * First one with sender IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->sender), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(md->sender_port) -#endif - ); - if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES - ? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")) - { - return FALSE; - } - - /* - * Second one with my IP & port - */ - _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, - is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie, - &(md->iface->addr), -#ifdef FORCE_NAT_TRAVERSAL - 0 -#else - ntohs(st->st_connection->spd.this.host_port) -#endif - ); - return (out_generic_raw(np, &isakmp_nat_d, outs, - hash, st->st_oakley.hasher->hash_digest_len, "NAT-D")); -} - -/* - * nat_traversal_natoa_lookup() - * - * Look for NAT-OA in message - */ -void nat_traversal_natoa_lookup(struct msg_digest *md) -{ - struct payload_digest *p; - struct state *st = md->st; - int i; - ip_address ip; - - if (!st || !md->iface) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return; - } - - /* Initialize NAT-OA */ - anyaddr(AF_INET, &st->nat_oa); - - /* Count NAT-OA **/ - for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++); - - DBG(DBG_NATT, - DBG_log("NAT-Traversal: received %d NAT-OA.", i) - ) - - if (i == 0) - return; - - if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "ignored because peer is not NATed", i); - return; - } - - if (i > 1) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " - "using first, ignoring others", i); - } - - /* Take first */ - p = md->chain[ISAKMP_NEXT_NATOA_RFC]; - - DBG(DBG_PARSING, - DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs)); - ); - - switch (p->payload.nat_oa.isanoa_idtype) - { - case ID_IPV4_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - case ID_IPV6_ADDR: - if (pbs_left(&p->pbs) == sizeof(struct in6_addr)) - { - initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip); - } - else - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA " - "with invalid IP size (%d)", (int)pbs_left(&p->pbs)); - return; - } - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid ID Type (%d) in NAT-OA - ignored", - p->payload.nat_oa.isanoa_idtype); - return; - } - - DBG(DBG_NATT, - { - char ip_t[ADDRTOT_BUF]; - addrtot(&ip, 0, ip_t, sizeof(ip_t)); - - DBG_log("received NAT-OA: %s", ip_t); - } - ) - - if (isanyaddr(&ip)) - loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA..."); - else - st->nat_oa = ip; -} - -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st) -{ - struct isakmp_nat_oa natoa; - pb_stream pbs; - unsigned char ip_val[sizeof(struct in6_addr)]; - size_t ip_len = 0; - ip_address *ip; - - if ((!st) || (!st->st_connection)) - { - loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d" - , __FILE__, __LINE__); - return FALSE; - } - ip = &(st->st_connection->spd.this.host_addr); - - memset(&natoa, 0, sizeof(natoa)); - natoa.isanoa_np = np; - - switch (addrtypeof(ip)) - { - case AF_INET: - ip_len = sizeof(ip->u.v4.sin_addr.s_addr); - memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len); - natoa.isanoa_idtype = ID_IPV4_ADDR; - break; - case AF_INET6: - ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr); - memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len); - natoa.isanoa_idtype = ID_IPV6_ADDR; - break; - default: - loglog(RC_LOG_SERIOUS, "NAT-Traversal: " - "invalid addrtypeof()=%d", addrtypeof(ip)); - return FALSE; - } - - if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs)) - return FALSE; - - if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA")) - return FALSE; - - DBG(DBG_NATT, - DBG_dump("NAT-OA (S):", ip_val, ip_len) - ) - - close_output_pbs(&pbs); - return TRUE; -} - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport) -{ - const char *mth = NULL, *rslt = NULL; - - switch (nt & NAT_TRAVERSAL_METHOD) - { - case LELEM(NAT_TRAVERSAL_IETF_00_01): - mth = natt_type_bitnames[0]; - break; - case LELEM(NAT_TRAVERSAL_IETF_02_03): - mth = natt_type_bitnames[1]; - break; - case LELEM(NAT_TRAVERSAL_RFC): - mth = natt_type_bitnames[2]; - break; - } - - switch (nt & NAT_T_DETECTED) - { - case 0: - rslt = "no NAT detected"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME): - rslt = "i am NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "peer is NATed"; - break; - case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER): - rslt = "both are NATed"; - break; - } - - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: Result using %s: %s", - mth ? mth : "unknown method", - rslt ? rslt : "unknown result" - ); - - if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)) - && (sport == IKE_UDP_PORT) - && ((nt & NAT_T_WITH_PORT_FLOATING)==0)) - { - loglog(RC_LOG_SERIOUS, - "Warning: peer is NATed but source port is still udp/%d. " - "Ipsec-passthrough NAT device suspected -- NAT-T may not work.", - IKE_UDP_PORT - ); - } -} - -int nat_traversal_espinudp_socket (int sk, u_int32_t type) -{ - int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type)); - - if (r < 0 && errno == ENOPROTOOPT) - { - loglog(RC_LOG_SERIOUS, - "NAT-Traversal: ESPINUDP(%d) not supported by kernel -- " - "NAT-T disabled", type); - disable_nat_traversal(type); - } - return r; -} - -void nat_traversal_new_ka_event (void) -{ - if (_ka_evt) - return; /* event already scheduled */ - - event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL); - _ka_evt = 1; -} - -static void nat_traversal_send_ka (struct state *st) -{ - static unsigned char ka_payload = 0xff; - chunk_t sav; - - DBG(DBG_NATT, - DBG_log("ka_event: send NAT-KA to %s:%d", - ip_str(&st->st_connection->spd.that.host_addr), - st->st_connection->spd.that.host_port); - ) - - /* save state chunk */ - sav = st->st_tpacket; - - /* send keep alive */ - st->st_tpacket = chunk_create(&ka_payload, 1); - send_packet(st, "NAT-T Keep Alive"); - - /* restore state chunk */ - st->st_tpacket = sav; -} - -/** - * Find ISAKMP States with NAT-T and send keep-alive - */ -static void nat_traversal_ka_event_state (struct state *st, void *data) -{ - unsigned int *_kap_st = (unsigned int *)data; - const connection_t *c = st->st_connection; - - if (!c) - return; - - if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4) - && (st->nat_traversal & NAT_T_DETECTED) - && ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - /* - * - ISAKMP established - * - NAT-Traversal detected - * - NAT-KeepAlive needed (we are NATed) - */ - if (c->newest_isakmp_sa != st->st_serialno) - { - /* - * if newest is also valid, ignore this one, we will only use - * newest. - */ - struct state *st_newest; - - st_newest = state_with_serialno(c->newest_isakmp_sa); - if (st_newest - && (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4) - && (st_newest->nat_traversal & NAT_T_DETECTED) - && ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka)) - { - return; - } - } - set_cur_state(st); - nat_traversal_send_ka(st); - reset_cur_state(); - (*_kap_st)++; - } -} - -void nat_traversal_ka_event (void) -{ - unsigned int _kap_st = 0; - - _ka_evt = 0; /* ready to be reschedule */ - - for_each_state((void *)nat_traversal_ka_event_state, &_kap_st); - - /* if there are still states who needs Keep-Alive, schedule new event */ - if (_kap_st) - nat_traversal_new_ka_event(); -} - -struct _new_mapp_nfo { - ip_address addr; - u_int16_t sport, dport; -}; - -static void nat_traversal_find_new_mapp_state (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data; - - if (c != NULL - && sameaddr(&c->spd.that.host_addr, &(nfo->addr)) - && c->spd.that.host_port == nfo->sport) - { - - /* change host port */ - c->spd.that.host_port = nfo->dport; - - if (IS_IPSEC_SA_ESTABLISHED(st->st_state) - || IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) - { - if (!update_ipsec_sa(st)) - { - /* - * If ipsec update failed, restore old port or we'll - * not be able to update anymore. - */ - c->spd.that.host_port = nfo->sport; - } - } - } -} - -static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport, - const ip_address *dst, u_int16_t dport) -{ - char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF]; - struct _new_mapp_nfo nfo; - - addrtot(src, 0, srca, ADDRTOT_BUF); - addrtot(dst, 0, dsta, ADDRTOT_BUF); - - if (!sameaddr(src, dst)) - { - loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: " - "address change currently not supported [%s:%d,%s:%d]", - srca, sport, dsta, dport); - return -1; - } - - if (sport == dport) - { - /* no change */ - return 0; - } - - DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport); - - nfo.addr = *src; - nfo.sport = sport; - nfo.dport = dport; - - for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo); - - return 0; -} - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st) -{ - connection_t *c = st ? st->st_connection : NULL; - struct iface *i = NULL; - - if ((st == NULL) || (c == NULL)) - return; - - if (md) - { - /* - * If source port has changed, update (including other states and - * established kernel SA) - */ - if (c->spd.that.host_port != md->sender_port) - { - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - &c->spd.that.host_addr, md->sender_port); - } - - /* - * If interface type has changed, update local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float)) - { - c->spd.this.host_port = (md->iface->ike_float) - ? NAT_T_IKE_FLOAT_PORT : pluto_port; - - DBG(DBG_NATT, - DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port); - ); - } - } - - /* - * If we're initiator and NAT-T (with port floating) is detected, we - * need to change port (MAIN_I3 or QUICK_I1) - */ - if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1) - && (st->nat_traversal & NAT_T_WITH_PORT_FLOATING) - && (st->nat_traversal & NAT_T_DETECTED) - && (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT)) - { - DBG(DBG_NATT, - DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT); - ) - c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT; - c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT; - /* - * Also update pending connections or they will be deleted if uniqueids - * option is set. - */ - update_pending(st, st); - } - - /* - * Find valid interface according to local port (500/4500) - */ - if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float) - || (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float)) - { - for (i = interfaces; i != NULL; i = i->next) - { - if (sameaddr(&c->interface->addr, &i->addr) - && i->ike_float != c->interface->ike_float) - { - DBG(DBG_NATT, - DBG_log("NAT-T: using interface %s:%d", i->rname, - i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port); - ) - c->interface = i; - break; - } - } - } -} - -struct _new_kernel_mapp_nfo { - u_int32_t reqid; - u_int32_t spi; - ip_address *addr; -}; - -static void nat_t_new_kernel_mapp (struct state *st, void *data) -{ - connection_t *c = st->st_connection; - struct _new_kernel_mapp_nfo *nfo = (struct _new_kernel_mapp_nfo *)data; - - if (c != NULL && st->st_esp.present - && nfo->spi == st->st_esp.our_spi - && nfo->reqid == c->spd.reqid) - { - u_int16_t port = ntohs(portof(nfo->addr)); - - DBG(DBG_NATT, { - char text_said[SATOT_BUF]; - char olda[ADDRTOT_BUF]; - char newa[ADDRTOT_BUF]; - ip_said said; - - initsaid(&c->spd.that.host_addr, nfo->spi, SA_ESP, &said); - satot(&said, 0, text_said, SATOT_BUF); - addrtot(&c->spd.that.host_addr, 0, olda, ADDRTOT_BUF); - addrtot(nfo->addr, 0, newa, ADDRTOT_BUF); - - DBG_log("new kernel mapping %s %s:%d %s:%d", - text_said, olda, c->spd.that.host_port, newa, port); - }) - - nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port, - nfo->addr, port); - } -} - -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end) -{ - struct _new_kernel_mapp_nfo nfo = { - .reqid = reqid, - .spi = spi, - .addr = new_end, - }; - for_each_state((void *)nat_t_new_kernel_mapp, &nfo); -} - diff --git a/src/pluto/nat_traversal.h b/src/pluto/nat_traversal.h deleted file mode 100644 index 80bdaf787..000000000 --- a/src/pluto/nat_traversal.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (C) 2010 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * Copyright (C) 2002-2003 Mathieu Lafon - * Arkoon Network Security - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _NAT_TRAVERSAL_H -#define _NAT_TRAVERSAL_H - -#include "packet.h" - -#define NAT_TRAVERSAL_IETF_00_01 1 -#define NAT_TRAVERSAL_IETF_02_03 2 -#define NAT_TRAVERSAL_RFC 3 - -#define NAT_TRAVERSAL_NAT_BHND_ME 30 -#define NAT_TRAVERSAL_NAT_BHND_PEER 31 - -#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31)) - -/** - * NAT-Traversal methods which need NAT-D - */ -#define NAT_T_WITH_NATD \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which need NAT-OA - */ -#define NAT_T_WITH_NATOA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use NAT-KeepAlive - */ -#define NAT_T_WITH_KA \ - ( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \ - LELEM(NAT_TRAVERSAL_RFC) ) -/** - * NAT-Traversal methods which use floating port - */ -#define NAT_T_WITH_PORT_FLOATING \ - ( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal methods which use officials values (RFC) - */ -#define NAT_T_WITH_RFC_VALUES \ - ( LELEM(NAT_TRAVERSAL_RFC) ) - -/** - * NAT-Traversal detected - */ -#define NAT_T_DETECTED \ - ( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) ) - -/** - * NAT-T Port Floating - */ -#define NAT_T_IKE_FLOAT_PORT 4500 - -void init_nat_traversal (bool activate, unsigned int keep_alive_period, - bool fka, bool spf); - -extern bool nat_traversal_enabled; -extern bool nat_traversal_support_non_ike; -extern bool nat_traversal_support_port_floating; - -/** - * NAT-D - */ -void nat_traversal_natd_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs, - struct msg_digest *md); -#endif - -/** - * NAT-OA - */ -void nat_traversal_natoa_lookup(struct msg_digest *md); -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs, - struct state *st); -#endif - -/** - * NAT-keep_alive - */ -void nat_traversal_new_ka_event (void); -void nat_traversal_ka_event (void); - -void nat_traversal_show_result (u_int32_t nt, u_int16_t sport); - -int nat_traversal_espinudp_socket (int sk, u_int32_t type); - -/** - * Vendor ID - */ -#ifndef PB_STREAM_UNDEFINED -bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs); -#endif -u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid); - -void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st); - -/** - * New NAT mapping - */ -void process_nat_t_new_mapping(u_int32_t reqid, u_int32_t spi, - ip_address *new_end); - -/** - * IKE port floating - */ -bool -nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in); - -/** - * Encapsulation mode macro (see demux.c) - */ -#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \ - ((st)->nat_traversal & NAT_T_DETECTED) \ - ? ( ((nat_t_policy) & POLICY_TUNNEL) \ - ? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \ - : (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \ - ) \ - : ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \ - ? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \ - : (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \ - ) \ - ) \ - : ( ((st)->st_policy & POLICY_TUNNEL) \ - ? (ENCAPSULATION_MODE_TUNNEL) \ - : (ENCAPSULATION_MODE_TRANSPORT) \ - ) \ - ) - -#endif /* _NAT_TRAVERSAL_H */ - diff --git a/src/pluto/ocsp.c b/src/pluto/ocsp.c deleted file mode 100644 index c299e3d39..000000000 --- a/src/pluto/ocsp.c +++ /dev/null @@ -1,1558 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "x509.h" -#include "crl.h" -#include "ca.h" -#include "certs.h" -#include "smartcard.h" -#include "whack.h" -#include "keys.h" -#include "fetch.h" -#include "ocsp.h" - -#define NONCE_LENGTH 16 - -static const char *const cert_status_names[] = { - "good", - "revoked", - "unknown", - "undefined" -}; - - -static const char *const response_status_names[] = { - "successful", - "malformed request", - "internal error", - "try later", - "status #4", - "signature required", - "unauthorized" -}; - -/* response container */ -typedef struct response response_t; - -struct response { - chunk_t tbs; - identification_t *responder_id_name; - chunk_t responder_id_key; - time_t produced_at; - chunk_t responses; - chunk_t nonce; - int algorithm; - chunk_t signature; -}; - -const response_t empty_response = { - { NULL, 0 } , /* tbs */ - NULL , /* responder_id_name */ - { NULL, 0 } , /* responder_id_key */ - UNDEFINED_TIME, /* produced_at */ - { NULL, 0 } , /* single_response */ - { NULL, 0 } , /* nonce */ - OID_UNKNOWN , /* signature_algorithm */ - { NULL, 0 } /* signature */ -}; - -/* single response container */ -typedef struct single_response single_response_t; - -struct single_response { - single_response_t *next; - int hash_algorithm; - chunk_t issuer_name_hash; - chunk_t issuer_key_hash; - chunk_t serialNumber; - cert_status_t status; - time_t revocationTime; - crl_reason_t revocationReason; - time_t thisUpdate; - time_t nextUpdate; -}; - -const single_response_t empty_single_response = { - NULL , /* *next */ - OID_UNKNOWN , /* hash_algorithm */ - { NULL, 0 } , /* issuer_name_hash */ - { NULL, 0 } , /* issuer_key_hash */ - { NULL, 0 } , /* serial_number */ - CERT_UNDEFINED , /* status */ - UNDEFINED_TIME , /* revocationTime */ - CRL_REASON_UNSPECIFIED, /* revocationReason */ - UNDEFINED_TIME , /* this_update */ - UNDEFINED_TIME /* next_update */ -}; - - -/* list of single requests */ -typedef struct request_list request_list_t; -struct request_list { - chunk_t request; - request_list_t *next; -}; - -/* some OCSP specific prefabricated ASN.1 constants */ -static const chunk_t ASN1_nonce_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x02 -); -static const chunk_t ASN1_response_oid = chunk_from_chars( - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x04 -); -static const chunk_t ASN1_response_content = chunk_from_chars( - 0x04, 0x0D, - 0x30, 0x0B, - 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01 -); - -/* default OCSP uri */ -static chunk_t ocsp_default_uri; - -/* ocsp cache: pointer to first element */ -static ocsp_location_t *ocsp_cache = NULL; - -/* static temporary storage for ocsp requestor information */ -static cert_t *ocsp_requestor_cert = NULL; - -static smartcard_t *ocsp_requestor_sc = NULL; - -static private_key_t *ocsp_requestor_key = NULL; - -/** - * ASN.1 definition of ocspResponse - */ -static const asn1Object_t ocspResponseObjects[] = { - { 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */ - { 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */ - { 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */ - { 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */ - { 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define OCSP_RESPONSE_STATUS 1 -#define OCSP_RESPONSE_TYPE 4 -#define OCSP_RESPONSE 5 - -/** - * ASN.1 definition of basicResponse - */ -static const asn1Object_t basicResponseObjects[] = { - { 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */ - { 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE | - ASN1_DEF }, /* 2 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */ - { 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */ - { 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */ - { 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */ - { 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */ - { 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */ - { 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */ - { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */ - { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */ - { 5, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 16 */ - { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */ - { 3, "end loop", ASN1_EOC, ASN1_END }, /* 18 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */ - { 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */ - { 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */ - { 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */ - { 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 26 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define BASIC_RESPONSE_TBS_DATA 1 -#define BASIC_RESPONSE_VERSION 3 -#define BASIC_RESPONSE_ID_BY_NAME 5 -#define BASIC_RESPONSE_ID_BY_KEY 8 -#define BASIC_RESPONSE_PRODUCED_AT 10 -#define BASIC_RESPONSE_RESPONSES 11 -#define BASIC_RESPONSE_EXT_ID 15 -#define BASIC_RESPONSE_CRITICAL 16 -#define BASIC_RESPONSE_EXT_VALUE 17 -#define BASIC_RESPONSE_ALGORITHM 20 -#define BASIC_RESPONSE_SIGNATURE 21 -#define BASIC_RESPONSE_CERTIFICATE 24 - -/** - * ASN.1 definition of responses - */ -static const asn1Object_t responsesObjects[] = { - { 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ - { 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */ - { 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define RESPONSES_SINGLE_RESPONSE 1 - -/** - * ASN.1 definition of singleResponse - */ -static const asn1Object_t singleResponseObjects[] = { - { 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */ - { 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */ - { 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */ - { 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */ - { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */ - { 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */ - { 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */ - { 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */ - { 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */ - { 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */ - { 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */ - { 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */ - { 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */ - { 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */ - { 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */ - { 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */ - { 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */ - { 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */ - { 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */ - { 4, "critical", ASN1_BOOLEAN, ASN1_BODY | - ASN1_DEF }, /* 24 */ - { 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */ - { 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 27 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define SINGLE_RESPONSE_ALGORITHM 2 -#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3 -#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4 -#define SINGLE_RESPONSE_SERIAL_NUMBER 5 -#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6 -#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8 -#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9 -#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11 -#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14 -#define SINGLE_RESPONSE_THIS_UPDATE 16 -#define SINGLE_RESPONSE_NEXT_UPDATE 18 -#define SINGLE_RESPONSE_EXT_ID 23 -#define SINGLE_RESPONSE_CRITICAL 24 -#define SINGLE_RESPONSE_EXT_VALUE 25 - -/* - * Build an ocsp location from certificate information - * without unsharing its contents - */ -static bool build_ocsp_location(const cert_t *cert, ocsp_location_t *location) -{ - certificate_t *certificate = cert->cert; - identification_t *issuer = certificate->get_issuer(certificate); - x509_t *x509 = (x509_t*)certificate; - chunk_t issuer_dn = issuer->get_encoding(issuer); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - hasher_t *hasher; - static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */ - - enumerator_t *enumerator = x509->create_ocsp_uri_enumerator(x509); - - location->uri = NULL; - while (enumerator->enumerate(enumerator, &location->uri)) - { - break; - } - enumerator->destroy(enumerator); - - if (location->uri == NULL) - { - ca_info_t *ca = get_ca_info(issuer, authKeyID); - if (ca && ca->ocspuri) - { - location->uri = ca->ocspuri; - } - else - { /* abort if no ocsp location uri is defined */ - return FALSE; - } - } - - /* compute authNameID from as SHA-1 hash of issuer DN */ - location->authNameID = chunk_create(digest, HASH_SIZE_SHA1); - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return FALSE; - } - hasher->get_hash(hasher, issuer_dn, digest); - hasher->destroy(hasher); - - location->next = NULL; - location->issuer = issuer; - location->authKeyID = authKeyID; - - if (authKeyID.ptr == NULL) - { - cert_t *authcert = get_authcert(issuer, authKeyID, X509_CA); - - if (authcert) - { - x509_t *x509 = (x509_t*)authcert->cert; - - location->authKeyID = x509->get_subjectKeyIdentifier(x509); - } - } - - location->nonce = chunk_empty; - location->certinfo = NULL; - - return TRUE; -} - -/** - * Compare two ocsp locations for equality - */ -static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b) -{ - return ((a->authKeyID.ptr) - ? same_keyid(a->authKeyID, b->authKeyID) - : a->issuer->equals(a->issuer, b->issuer)) - && streq(a->uri, b->uri); -} - -/** - * Find an existing ocsp location in a chained list - */ -ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain) -{ - - while (chain) - { - if (same_ocsp_location(loc, chain)) - return chain; - chain = chain->next; - } - return NULL; -} - -/** - * Retrieves the status of a cert from the ocsp cache - * returns CERT_UNDEFINED if no status is found - */ -static cert_status_t get_ocsp_status(const ocsp_location_t *loc, - chunk_t serialNumber, - time_t *nextUpdate, time_t *revocationTime, - crl_reason_t *revocationReason) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - /* find location */ - ocsp_location_t *location = get_ocsp_location(loc, ocsp_cache); - - if (location == NULL) - return CERT_UNDEFINED; - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp == 0) - { - *nextUpdate = certinfo->nextUpdate; - *revocationTime = certinfo->revocationTime; - *revocationReason = certinfo->revocationReason; - return certinfo->status; - } - - return CERT_UNDEFINED; -} - -/** - * Verify the ocsp status of a certificate - */ -cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until, - time_t *revocationDate, - crl_reason_t *revocationReason) -{ - x509_t *x509 = (x509_t*)cert->cert; - chunk_t serialNumber = x509->get_serial(x509); - cert_status_t status; - ocsp_location_t location; - time_t nextUpdate = UNDEFINED_TIME; - - *revocationDate = UNDEFINED_TIME; - *revocationReason = CRL_REASON_UNSPECIFIED; - - /* is an ocsp location defined? */ - if (!build_ocsp_location(cert, &location)) - { - return CERT_UNDEFINED; - } - - lock_ocsp_cache("verify_by_ocsp"); - status = get_ocsp_status(&location, serialNumber, &nextUpdate - , revocationDate, revocationReason); - unlock_ocsp_cache("verify_by_ocsp"); - - if (status == CERT_UNDEFINED || nextUpdate < time(NULL)) - { - plog("ocsp status is stale or not in cache"); - add_ocsp_fetch_request(&location, serialNumber); - - /* inititate fetching of ocsp status */ - wake_fetch_thread("verify_by_ocsp"); - } - *until = nextUpdate; - return status; -} - -/** - * Check if an ocsp status is about to expire - */ -void check_ocsp(void) -{ - ocsp_location_t *location; - - lock_ocsp_cache("check_ocsp"); - location = ocsp_cache; - - while (location) - { - char buf[BUF_LEN]; - bool first = TRUE; - ocsp_certinfo_t *certinfo = location->certinfo; - - while (certinfo) - { - if (!certinfo->once) - { - time_t time_left = certinfo->nextUpdate - time(NULL); - - DBG(DBG_CONTROL, - if (first) - { - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - datatot(location->authKeyID.ptr, location->authKeyID.len - , ':', buf, BUF_LEN); - DBG_log("authkey: %s", buf); - } - first = FALSE; - } - datatot(certinfo->serialNumber.ptr, certinfo->serialNumber.len - , ':', buf, BUF_LEN); - DBG_log("serial: %s, %ld seconds left", buf, time_left) - ) - - if (time_left < 2*crl_check_interval) - add_ocsp_fetch_request(location, certinfo->serialNumber); - } - certinfo = certinfo->next; - } - location = location->next; - } - unlock_ocsp_cache("check_ocsp"); -} - -/** - * frees the allocated memory of a certinfo struct - */ -static void free_certinfo(ocsp_certinfo_t *certinfo) -{ - free(certinfo->serialNumber.ptr); - free(certinfo); -} - -/** - * frees all certinfos in a chained list - */ -static void free_certinfos(ocsp_certinfo_t *chain) -{ - ocsp_certinfo_t *certinfo; - - while (chain) - { - certinfo = chain; - chain = chain->next; - free_certinfo(certinfo); - } -} - -/** - * Frees the memory allocated to an ocsp location including all certinfos - */ -static void free_ocsp_location(ocsp_location_t* location) -{ - DESTROY_IF(location->issuer); - free(location->authNameID.ptr); - free(location->authKeyID.ptr); - free(location->uri); - free_certinfos(location->certinfo); - free(location); -} - -/* - * Free a chained list of ocsp locations - */ -void free_ocsp_locations(ocsp_location_t **chain) -{ - while (*chain) - { - ocsp_location_t *location = *chain; - *chain = location->next; - free_ocsp_location(location); - } -} - -/** - * Free the ocsp cache - */ -void free_ocsp_cache(void) -{ - lock_ocsp_cache("free_ocsp_cache"); - free_ocsp_locations(&ocsp_cache); - unlock_ocsp_cache("free_ocsp_cache"); -} - -/** - * Frees the ocsp cache and global variables - */ -void free_ocsp(void) -{ - free(ocsp_default_uri.ptr); - free_ocsp_cache(); -} - -/** - * List a chained list of ocsp_locations - */ -void list_ocsp_locations(ocsp_location_t *location, bool requests, - bool utc, bool strict) -{ - bool first = TRUE; - - while (location) - { - ocsp_certinfo_t *certinfo = location->certinfo; - - if (certinfo) - { - if (first) - { - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of OCSP %s:", requests ? - "Fetch Requests" : "Responses"); - first = FALSE; - } - whack_log(RC_COMMENT, " "); - if (location->issuer) - { - whack_log(RC_COMMENT, " issuer: \"%Y\"", location->issuer); - } - whack_log(RC_COMMENT, " uri: '%s'", location->uri); - if (location->authNameID.ptr) - { - whack_log(RC_COMMENT, " authname: %#B", &location->authNameID); - } - if (location->authKeyID.ptr) - { - whack_log(RC_COMMENT, " authkey: %#B", &location->authKeyID); - } - while (certinfo) - { - chunk_t serial = chunk_skip_zero(certinfo->serialNumber); - - if (requests) - { - whack_log(RC_COMMENT, " serial: %#B, %d trials", - &serial, certinfo->trials); - } - else if (certinfo->once) - { - whack_log(RC_COMMENT, " serial: %#B, %s, once%s", - &serial, cert_status_names[certinfo->status], - (certinfo->nextUpdate < time(NULL))? " (expired)": ""); - } - else - { - whack_log(RC_COMMENT, " serial: %#B, %s, until %T %s", - &serial, cert_status_names[certinfo->status], - &certinfo->nextUpdate, utc, - check_expiry(certinfo->nextUpdate, OCSP_WARNING_INTERVAL, strict)); - } - certinfo = certinfo->next; - } - } - location = location->next; - } -} - -/** - * List the ocsp cache - */ -void list_ocsp_cache(bool utc, bool strict) -{ - lock_ocsp_cache("list_ocsp_cache"); - list_ocsp_locations(ocsp_cache, FALSE, utc, strict); - unlock_ocsp_cache("list_ocsp_cache"); -} - -static bool get_ocsp_requestor_cert(ocsp_location_t *location) -{ - cert_t *cert = NULL; - - /* initialize temporary static storage */ - ocsp_requestor_cert = NULL; - ocsp_requestor_sc = NULL; - ocsp_requestor_key = NULL; - - for (;;) - { - certificate_t *certificate; - - /* looking for a certificate from the same issuer */ - cert = get_x509cert(location->issuer, location->authKeyID, cert); - if (cert == NULL) - { - break; - } - certificate = cert->cert; - DBG(DBG_CONTROL, - DBG_log("candidate: '%Y'", certificate->get_subject(certificate)); - ) - - if (cert->smartcard) - { - /* look for a matching private key on a smartcard */ - smartcard_t *sc = scx_get(cert); - - if (sc) - { - DBG(DBG_CONTROL, - DBG_log("matching smartcard found") - ) - if (sc->valid) - { - ocsp_requestor_cert = cert; - ocsp_requestor_sc = sc; - return TRUE; - } - plog("unable to sign ocsp request without PIN"); - } - } - else - { - /* look for a matching private key in the chained list */ - private_key_t *private = get_x509_private_key(cert); - - if (private) - { - DBG(DBG_CONTROL, - DBG_log("matching private key found") - ) - ocsp_requestor_cert = cert; - ocsp_requestor_key = private; - return TRUE; - } - } - } - return FALSE; -} - -static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc) -{ - hasher_t *hasher; - u_char *pos; - chunk_t digest; - chunk_t digest_info, sigdata; - size_t siglen = 0; - - if (!scx_establish_context(sc) || !scx_login(sc)) - { - scx_release_context(sc); - return chunk_empty; - } - - siglen = scx_get_keylength(sc); - - if (siglen == 0) - { - plog("failed to get keylength from smartcard"); - scx_release_context(sc); - return chunk_empty; - } - - DBG(DBG_CONTROL | DBG_CRYPT, - DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)" - , (int)sc->slot, sc->id) - ) - - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (hasher == NULL) - { - return chunk_empty; - } - hasher->allocate_hash(hasher, tbs, &digest); - hasher->destroy(hasher); - - /* according to PKCS#1 v2.1 digest must be packaged into - * an ASN.1 structure for encryption - */ - digest_info = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_wrap(ASN1_OCTET_STRING, "m", digest)); - - pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen); - *pos++ = 0x00; - scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen); - free(digest_info.ptr); - - if (!pkcs11_keep_state) - { - scx_release_context(sc); - } - return sigdata; -} - -/** - * build signature into ocsp request gets built only if a request cert - * with a corresponding private key is found - */ -static chunk_t build_signature(chunk_t tbsRequest) -{ - chunk_t sigdata, cert, certs = chunk_empty; - - if (ocsp_requestor_sc) - { - /* RSA signature is done on smartcard */ - sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc); - } - else - { - /* RSA signature is done in software */ - sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key, - TRUE); - } - if (sigdata.ptr == NULL) - { - return chunk_empty; - } - - /* include our certificate */ - if (ocsp_requestor_cert->cert->get_encoding(ocsp_requestor_cert->cert, - CERT_ASN1_DER, &cert)) - { - certs = asn1_wrap(ASN1_CONTEXT_C_0, "m", - asn1_wrap(ASN1_SEQUENCE, "m", cert)); - } - /* build signature comprising algorithm, signature and cert */ - return asn1_wrap(ASN1_CONTEXT_C_0, "m" - , asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_algorithmIdentifier(OID_SHA1_WITH_RSA) - , sigdata - , certs - ) - ); -} - -/** - * Build request (into requestList) - * no singleRequestExtensions used - */ -static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo) -{ - chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "mmmm" - , asn1_algorithmIdentifier(OID_SHA1) - , asn1_simple_object(ASN1_OCTET_STRING, location->authNameID) - , asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID) - , asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber)); - - return asn1_wrap(ASN1_SEQUENCE, "m", reqCert); -} - -/** - * build requestList (into TBSRequest) - */ -static chunk_t build_request_list(ocsp_location_t *location) -{ - chunk_t requestList; - request_list_t *reqs = NULL; - ocsp_certinfo_t *certinfo = location->certinfo; - u_char *pos; - - size_t datalen = 0; - - /* build content */ - while (certinfo) - { - /* build request for every certificate in list - * and store them in a chained list - */ - request_list_t *req = malloc_thing(request_list_t); - - req->request = build_request(location, certinfo); - req->next = reqs; - reqs = req; - - datalen += req->request.len; - certinfo = certinfo->next; - } - - pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen); - - /* copy all in chained list, free list afterwards */ - while (reqs) - { - request_list_t *req = reqs; - - mv_chunk(&pos, req->request); - reqs = reqs->next; - free(req); - } - - return requestList; -} - -/** - * Build requestorName (into TBSRequest) - */ -static chunk_t build_requestor_name(void) -{ - certificate_t *certificate = ocsp_requestor_cert->cert; - identification_t *subject = certificate->get_subject(certificate); - - return asn1_wrap(ASN1_CONTEXT_C_1, "m" - , asn1_simple_object(ASN1_CONTEXT_C_4 - , subject->get_encoding(subject))); -} - -/** - * build nonce extension (into requestExtensions) - */ -static chunk_t build_nonce_extension(ocsp_location_t *location) -{ - rng_t *rng; - - /* generate a random nonce */ - location->nonce.ptr = malloc(NONCE_LENGTH), - location->nonce.len = NONCE_LENGTH; - rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); - rng->get_bytes(rng, location->nonce.len, location->nonce.ptr); - rng->destroy(rng); - - return asn1_wrap(ASN1_SEQUENCE, "cm" - , ASN1_nonce_oid - , asn1_simple_object(ASN1_OCTET_STRING, location->nonce)); -} - -/** - * Build requestExtensions (into TBSRequest) - */ -static chunk_t build_request_ext(ocsp_location_t *location) -{ - return asn1_wrap(ASN1_CONTEXT_C_2, "m" - , asn1_wrap(ASN1_SEQUENCE, "mm" - , build_nonce_extension(location) - , asn1_wrap(ASN1_SEQUENCE, "cc" - , ASN1_response_oid - , ASN1_response_content - ) - ) - ); -} - -/** - * Build TBSRequest (into OCSPRequest) - */ -static chunk_t build_tbs_request(ocsp_location_t *location, bool has_requestor_cert) -{ - /* version is skipped since the default is ok */ - return asn1_wrap(ASN1_SEQUENCE, "mmm" - , (has_requestor_cert) - ? build_requestor_name() - : chunk_empty - , build_request_list(location) - , build_request_ext(location)); -} - -/** - * Assembles an ocsp request to given location - * and sets nonce field in location to the sent nonce - */ -chunk_t build_ocsp_request(ocsp_location_t *location) -{ - bool has_requestor_cert; - chunk_t tbsRequest, signature; - - DBG(DBG_CONTROL, - DBG_log("assembling ocsp request"); - DBG_log("issuer: \"%Y\"", location->issuer); - if (location->authKeyID.ptr) - { - DBG_log("authkey: %#B", &location->authKeyID); - } - ) - lock_certs_and_keys("build_ocsp_request"); - - /* looks for requestor cert and matching private key */ - has_requestor_cert = get_ocsp_requestor_cert(location); - - /* build content */ - tbsRequest = build_tbs_request(location, has_requestor_cert); - - /* sign tbsReuqest */ - signature = (has_requestor_cert)? build_signature(tbsRequest) - : chunk_empty; - - unlock_certs_and_keys("build_ocsp_request"); - - return asn1_wrap(ASN1_SEQUENCE, "mm" - , tbsRequest - , signature); -} - -/** - * Check if the OCSP response has a valid signature - */ -static bool valid_ocsp_response(response_t *res) -{ - int pathlen, pathlen_constraint; - cert_t *authcert; - - lock_authcert_list("valid_ocsp_response"); - - authcert = get_authcert(res->responder_id_name, res->responder_id_key, - X509_OCSP_SIGNER | X509_CA); - if (authcert == NULL) - { - plog("no matching ocsp signer cert found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("ocsp signer cert found") - ) - - if (!x509_check_signature(res->tbs, res->signature, res->algorithm, - authcert->cert)) - { - plog("signature of ocsp response is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("signature of ocsp response is valid") - ) - - - for (pathlen = -1; pathlen <= X509_MAX_PATH_LEN; pathlen++) - { - cert_t *cert = authcert; - certificate_t *certificate = cert->cert; - x509_t *x509 = (x509_t*)certificate; - identification_t *subject = certificate->get_subject(certificate); - identification_t *issuer = certificate->get_issuer(certificate); - chunk_t authKeyID = x509->get_authKeyIdentifier(x509); - time_t not_before, not_after; - - DBG(DBG_CONTROL, - DBG_log("subject: '%Y'", subject); - DBG_log("issuer: '%Y'", issuer); - if (authKeyID.ptr) - { - DBG_log("authkey: %#B", &authKeyID); - } - ) - - if (!certificate->get_validity(certificate, NULL, ¬_before, ¬_after)) - { - plog("certificate is invalid (valid from %T to %T)", - ¬_before, FALSE, ¬_after, FALSE); - - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate is valid") - ) - - authcert = get_authcert(issuer, authKeyID, X509_CA); - if (authcert == NULL) - { - plog("issuer cacert not found"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("issuer cacert found") - ) - - if (!certificate->issued_by(certificate, authcert->cert)) - { - plog("certificate signature is invalid"); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; - } - DBG(DBG_CONTROL, - DBG_log("certificate signature is valid") - ) - - /* check path length constraint */ - pathlen_constraint = x509->get_constraint(x509, X509_PATH_LEN); - if (pathlen_constraint != X509_NO_CONSTRAINT && - pathlen > pathlen_constraint) - { - plog("path length of %d violates constraint of %d", - pathlen, pathlen_constraint); - return FALSE; - } - - /* check if cert is self-signed */ - if (x509->get_flags(x509) & X509_SELF_SIGNED) - { - DBG(DBG_CONTROL, - DBG_log("reached self-signed root ca with a path length of %d", - pathlen) - ) - unlock_authcert_list("valid_ocsp_response"); - return TRUE; - } - } - plog("maximum path length of %d exceeded", X509_MAX_PATH_LEN); - unlock_authcert_list("valid_ocsp_response"); - return FALSE; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res) -{ - asn1_parser_t *parser; - chunk_t object; - u_int version; - int objectID; - int extn_oid = OID_UNKNOWN; - bool success = FALSE; - bool critical; - - parser = asn1_parser_create(basicResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case BASIC_RESPONSE_TBS_DATA: - res->tbs = object; - break; - case BASIC_RESPONSE_VERSION: - version = (object.len)? (1 + (u_int)*object.ptr) : 1; - if (version != OCSP_BASIC_RESPONSE_VERSION) - { - plog("wrong ocsp basic response version (version= %i)", version); - goto end; - } - break; - case BASIC_RESPONSE_ID_BY_NAME: - res->responder_id_name = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG(DBG_PARSING, - DBG_log(" '%Y'", res->responder_id_name) - ) - break; - case BASIC_RESPONSE_ID_BY_KEY: - res->responder_id_key = object; - break; - case BASIC_RESPONSE_PRODUCED_AT: - res->produced_at = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case BASIC_RESPONSE_RESPONSES: - res->responses = object; - break; - case BASIC_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case BASIC_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - break; - case BASIC_RESPONSE_EXT_VALUE: - if (extn_oid == OID_NONCE) - res->nonce = object; - break; - case BASIC_RESPONSE_ALGORITHM: - res->algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case BASIC_RESPONSE_SIGNATURE: - res->signature = object; - break; - case BASIC_RESPONSE_CERTIFICATE: - { - cert_t *cert = malloc_thing(cert_t); - x509_t *x509; - - *cert = cert_empty; - cert->cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert->cert == NULL) - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("parsing of embedded ocsp certificate failed") - ) - cert_free(cert); - break; - } - x509 = (x509_t*)cert->cert; - - if ((x509->get_flags(x509) & X509_OCSP_SIGNER) && - trust_authcert_candidate(cert, NULL)) - { - add_authcert(cert, X509_OCSP_SIGNER); - } - else - { - DBG(DBG_CONTROL | DBG_PARSING, - DBG_log("embedded ocsp certificate rejected") - ) - cert_free(cert); - } - } - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; - -} - - -/** - * Parse an ocsp response and return the result as a response_t struct - */ -static response_status parse_ocsp_response(chunk_t blob, response_t * res) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - int ocspResponseType = OID_UNKNOWN; - bool success = FALSE; - response_status rStatus = STATUS_INTERNALERROR; - - parser = asn1_parser_create(ocspResponseObjects, blob); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) { - case OCSP_RESPONSE_STATUS: - rStatus = (response_status) *object.ptr; - - switch (rStatus) - { - case STATUS_SUCCESSFUL: - break; - case STATUS_MALFORMEDREQUEST: - case STATUS_INTERNALERROR: - case STATUS_TRYLATER: - case STATUS_SIGREQUIRED: - case STATUS_UNAUTHORIZED: - plog("ocsp response: server said '%s'" - , response_status_names[rStatus]); - goto end; - default: - goto end; - } - break; - case OCSP_RESPONSE_TYPE: - ocspResponseType = asn1_known_oid(object); - break; - case OCSP_RESPONSE: - { - switch (ocspResponseType) { - case OID_BASIC: - success = parse_basic_ocsp_response(object, - parser->get_level(parser)+1, res); - break; - default: - DBG(DBG_CONTROL, - DBG_log("ocsp response is not of type BASIC"); - DBG_dump_chunk("ocsp response OID: ", object); - ) - goto end; - } - } - break; - } - } - success &= parser->success(parser); - -end: - parser->destroy(parser); - return rStatus; -} - -/** - * Parse a basic OCSP response - */ -static bool parse_ocsp_single_response(chunk_t blob, int level0, - single_response_t *sres) -{ - asn1_parser_t *parser; - chunk_t object; - u_int extn_oid; - int objectID; - bool critical; - bool success = FALSE; - - parser = asn1_parser_create(singleResponseObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - switch (objectID) - { - case SINGLE_RESPONSE_ALGORITHM: - sres->hash_algorithm = asn1_parse_algorithmIdentifier(object, - parser->get_level(parser)+1, NULL); - break; - case SINGLE_RESPONSE_ISSUER_NAME_HASH: - sres->issuer_name_hash = object; - break; - case SINGLE_RESPONSE_ISSUER_KEY_HASH: - sres->issuer_key_hash = object; - break; - case SINGLE_RESPONSE_SERIAL_NUMBER: - sres->serialNumber = object; - break; - case SINGLE_RESPONSE_CERT_STATUS_GOOD: - sres->status = CERT_GOOD; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOKED: - sres->status = CERT_REVOKED; - break; - case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME: - sres->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON: - sres->revocationReason = (object.len == 1) - ? *object.ptr : CRL_REASON_UNSPECIFIED; - break; - case SINGLE_RESPONSE_CERT_STATUS_UNKNOWN: - sres->status = CERT_UNKNOWN; - break; - case SINGLE_RESPONSE_THIS_UPDATE: - sres->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_NEXT_UPDATE: - sres->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME); - break; - case SINGLE_RESPONSE_EXT_ID: - extn_oid = asn1_known_oid(object); - break; - case SINGLE_RESPONSE_CRITICAL: - critical = object.len && *object.ptr; - DBG(DBG_PARSING, - DBG_log(" %s",(critical)?"TRUE":"FALSE"); - ) - case SINGLE_RESPONSE_EXT_VALUE: - break; - } - } - success = parser->success(parser); - parser->destroy(parser); - return success; -} - -/** - * Add an ocsp location to a chained list - */ -ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc, - ocsp_location_t **chain) -{ - ocsp_location_t *location = malloc_thing(ocsp_location_t); - - /* unshare location fields */ - location->issuer = loc->issuer->clone(loc->issuer); - location->authNameID = chunk_clone(loc->authNameID); - location->authKeyID = chunk_clone(loc->authKeyID); - location->uri = strdup(loc->uri); - location->certinfo = NULL; - - /* insert new ocsp location in front of chain */ - location->next = *chain; - *chain = location; - - DBG(DBG_CONTROL, - DBG_log("new ocsp location added") - ) - - return location; -} - -/** - * add a certinfo struct to a chained list - */ -void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, - ocsp_location_t **chain, bool request) -{ - ocsp_location_t *location; - ocsp_certinfo_t *certinfo, **certinfop; - char buf[BUF_LEN]; - time_t now; - int cmp = -1; - - location = get_ocsp_location(loc, *chain); - if (location == NULL) - { - location = add_ocsp_location(loc, chain); - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(info->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - /* add a new certinfo entry */ - ocsp_certinfo_t *cnew = malloc_thing(ocsp_certinfo_t); - - cnew->serialNumber = chunk_clone(info->serialNumber); - cnew->next = certinfo; - cnew->trials = 0; - *certinfop = cnew; - certinfo = cnew; - } - - DBG(DBG_CONTROL, - datatot(info->serialNumber.ptr, info->serialNumber.len, ':' - , buf, BUF_LEN); - DBG_log("ocsp %s for serial %s %s" - , request?"fetch request":"certinfo" - , buf - , (cmp == 0)? (request?"already exists":"updated"):"added") - ) - - time(&now); - - if (request) - { - certinfo->status = CERT_UNDEFINED; - - if (cmp != 0) - { - certinfo->thisUpdate = now; - } - certinfo->nextUpdate = UNDEFINED_TIME; - } - else - { - certinfo->status = info->status; - certinfo->revocationTime = info->revocationTime; - certinfo->revocationReason = info->revocationReason; - - certinfo->thisUpdate = (info->thisUpdate != UNDEFINED_TIME)? - info->thisUpdate : now; - - certinfo->once = (info->nextUpdate == UNDEFINED_TIME); - - certinfo->nextUpdate = (certinfo->once)? - (now + OCSP_DEFAULT_VALID_TIME) : info->nextUpdate; - } -} - -/** - * Process received ocsp single response and add it to ocsp cache - */ -static void process_single_response(ocsp_location_t *location, - single_response_t *sres) -{ - ocsp_certinfo_t *certinfo, **certinfop; - int cmp = -1; - - if (sres->hash_algorithm != OID_SHA1) - { - plog("only SHA-1 hash supported in OCSP single response"); - return; - } - if (!(chunk_equals(sres->issuer_name_hash, location->authNameID) - && chunk_equals(sres->issuer_key_hash, location->authKeyID))) - { - plog("ocsp single response has wrong issuer"); - return; - } - - /* traverse list of certinfos in increasing order */ - certinfop = &location->certinfo; - certinfo = *certinfop; - - while (certinfo) - { - cmp = chunk_compare(sres->serialNumber, certinfo->serialNumber); - if (cmp <= 0) - break; - certinfop = &certinfo->next; - certinfo = *certinfop; - } - - if (cmp != 0) - { - plog("received unrequested cert status from ocsp server"); - return; - } - - /* unlink cert from ocsp fetch request list */ - *certinfop = certinfo->next; - - /* update certinfo using the single response information */ - certinfo->thisUpdate = sres->thisUpdate; - certinfo->nextUpdate = sres->nextUpdate; - certinfo->status = sres->status; - certinfo->revocationTime = sres->revocationTime; - certinfo->revocationReason = sres->revocationReason; - - /* add or update certinfo in ocsp cache */ - lock_ocsp_cache("process_single_response"); - add_certinfo(location, certinfo, &ocsp_cache, FALSE); - unlock_ocsp_cache("process_single_response"); - - /* free certinfo unlinked from ocsp fetch request list */ - free_certinfo(certinfo); -} - -/** - * Destroy a response_t object - */ -static void free_response(response_t *res) -{ - DESTROY_IF(res->responder_id_name); -} - -/** - * Parse and verify ocsp response and update the ocsp cache - */ -void parse_ocsp(ocsp_location_t *location, chunk_t blob) -{ - response_t res = empty_response; - - /* parse the ocsp response without looking at the single responses yet */ - response_status status = parse_ocsp_response(blob, &res); - - if (status != STATUS_SUCCESSFUL) - { - plog("error in ocsp response"); - goto free; - } - /* check if there was a nonce in the request */ - if (location->nonce.ptr && res.nonce.ptr == NULL) - { - plog("ocsp response contains no nonce, replay attack possible"); - } - /* check if the nonce is identical */ - if (res.nonce.ptr && !chunk_equals(res.nonce, location->nonce)) - { - plog("invalid nonce in ocsp response"); - goto free; - } - /* check if the response is signed by a trusted key */ - if (!valid_ocsp_response(&res)) - { - plog("invalid ocsp response"); - goto free; - } - DBG(DBG_CONTROL, - DBG_log("valid ocsp response") - ) - - /* now parse the single responses one at a time */ - { - asn1_parser_t *parser; - chunk_t object; - int objectID; - - parser = asn1_parser_create(responsesObjects, res.responses); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == RESPONSES_SINGLE_RESPONSE) - { - single_response_t sres = empty_single_response; - - if (!parse_ocsp_single_response(object, - parser->get_level(parser)+1, &sres)) - { - goto end; - } - process_single_response(location, &sres); - } - } -end: - parser->destroy(parser); - } - -free: - free_response(&res); -} diff --git a/src/pluto/ocsp.h b/src/pluto/ocsp.h deleted file mode 100644 index 977cca3c8..000000000 --- a/src/pluto/ocsp.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Support of the Online Certificate Status Protocol (OCSP) Support - * Copyright (C) 2003 Christoph Gysin, Simon Zwahlen - * Zuercher Hochschule Winterthur - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "constants.h" - -#include - -/* constants */ - -#define OCSP_BASIC_RESPONSE_VERSION 1 -#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */ -#define OCSP_WARNING_INTERVAL 2 /* days */ - -/* OCSP response status */ - -typedef enum { - STATUS_SUCCESSFUL = 0, - STATUS_MALFORMEDREQUEST = 1, - STATUS_INTERNALERROR = 2, - STATUS_TRYLATER = 3, - STATUS_SIGREQUIRED = 5, - STATUS_UNAUTHORIZED= 6 -} response_status; - -/* OCSP access structures */ - -typedef struct ocsp_certinfo ocsp_certinfo_t; - -struct ocsp_certinfo { - ocsp_certinfo_t *next; - int trials; - chunk_t serialNumber; - cert_status_t status; - bool once; - crl_reason_t revocationReason; - time_t revocationTime; - time_t thisUpdate; - time_t nextUpdate; -}; - -typedef struct ocsp_location ocsp_location_t; - -struct ocsp_location { - ocsp_location_t *next; - identification_t *issuer; - chunk_t authNameID; - chunk_t authKeyID; - chunk_t nonce; - char *uri; - ocsp_certinfo_t *certinfo; -}; - -extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t *chain); -extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc - , ocsp_location_t **chain); -extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info - , ocsp_location_t **chain, bool request); -extern void check_ocsp(void); -extern cert_status_t verify_by_ocsp(const cert_t *cert, time_t *until - , time_t *revocationTime, crl_reason_t *revocationReason); -extern bool ocsp_set_request_cert(char* path); -extern void ocsp_set_default_uri(char* uri); -extern void ocsp_cache_add_cert(const cert_t* cert); -extern chunk_t build_ocsp_request(ocsp_location_t* location); -extern void parse_ocsp(ocsp_location_t* location, chunk_t blob); -extern void list_ocsp_locations(ocsp_location_t *location, bool requests - , bool utc, bool strict); -extern void list_ocsp_cache(bool utc, bool strict); -extern void free_ocsp_locations(ocsp_location_t **chain); -extern void free_ocsp_cache(void); -extern void free_ocsp(void); -extern void ocsp_purge_cache(void); diff --git a/src/pluto/packet.c b/src/pluto/packet.c deleted file mode 100644 index 35fc4afcc..000000000 --- a/src/pluto/packet.c +++ /dev/null @@ -1,1242 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include - -#include - -#include "constants.h" -#include "defs.h" -#include "log.h" -#include "packet.h" -#include "whack.h" /* for RC_LOG_SERIOUS */ - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isa_fields[] = { - { ft_raw, COOKIE_SIZE, "initiator cookie", NULL }, - { ft_raw, COOKIE_SIZE, "responder cookie", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names }, - { ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names }, - { ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names }, - { ft_raw, 32/BITS_PER_BYTE, "message ID", NULL }, - { ft_len, 32/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) }; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -static field_desc isag_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) }; - - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* Oakley Attributes */ -static field_desc isaat_fields_oakley[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_oakley_attribute_desc = { - "ISAKMP Oakley attribute", - isaat_fields_oakley, sizeof(struct isakmp_attribute) }; - -/* IPsec DOI Attributes */ -static field_desc isaat_fields_ipsec[] = { - { ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_attribute_desc = { - "ISAKMP IPsec DOI attribute", - isaat_fields_ipsec, sizeof(struct isakmp_attribute) }; - -/* Mode Config Attributes */ -static field_desc isaat_fields_modecfg[] = { - { ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names }, - { ft_lv, 16/BITS_PER_BYTE, "length/value", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_modecfg_attribute_desc = { - "ISAKMP ModeCfg attribute", - isaat_fields_modecfg, sizeof(struct isakmp_attribute) }; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isasa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) }; - -static field_desc ipsec_sit_field[] = { - { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) }; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isap_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names }, - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) }; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - -/* PROTO_ISAKMP */ -static field_desc isat_fields_isakmp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_isakmp_transform_desc = { - "ISAKMP Transform Payload (ISAKMP)", - isat_fields_isakmp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_AH */ -static field_desc isat_fields_ah[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ah_transform_desc = { - "ISAKMP Transform Payload (AH)", - isat_fields_ah, sizeof(struct isakmp_transform) }; - -/* PROTO_IPSEC_ESP */ -static field_desc isat_fields_esp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transform_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_esp_transform_desc = { - "ISAKMP Transform Payload (ESP)", - isat_fields_esp, sizeof(struct isakmp_transform) }; - -/* PROTO_IPCOMP */ -static field_desc isat_fields_ipcomp[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names }, - { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipcomp_transform_desc = { - "ISAKMP Transform Payload (COMP)", - isat_fields_ipcomp, sizeof(struct isakmp_transform) }; - - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */ - { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */ - { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */ - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) }; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isaiid_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */ - { ft_nat, 16/BITS_PER_BYTE, "port", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) }; - -/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacert_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_certificate_desc cannot be - * sizeof(struct isakmp_cert) because that will rounded up for padding. - */ - struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE }; - -/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isacr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names }, - { ft_end, 0, NULL, NULL } -}; - -/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be - * sizeof(struct isakmp_cr) because that will rounded up for padding. - */ -struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE }; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isan_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", ¬ification_names }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) }; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isad_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names }, - { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */ - { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL }, - { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) }; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* MODECFG */ -/* - * From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -static field_desc isaattr_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) }; - -/* ISAKMP NAT-Traversal NAT-D - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! HASH of the address and port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) }; - -/* ISAKMP NAT-Traversal NAT-OA - * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2 - * - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! RESERVED ! RESERVED ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! IPv4 (4 octets) or IPv6 address (16 octets) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -static field_desc isanat_oa_fields[] = { - { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names }, - { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL }, - { ft_len, 16/BITS_PER_BYTE, "length", NULL }, - { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, - { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL }, - { ft_end, 0, NULL, NULL } -}; - -struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) }; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = { - NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */ - &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */ - NULL, /* 2 ISAKMP_NEXT_P (Proposal) */ - NULL, /* 3 ISAKMP_NEXT_T (Transform) */ - &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */ - NULL, /* 5 ISAKMP_NEXT_ID (Identification) */ - &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */ - &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */ - &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */ - &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */ - &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */ - &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */ - &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */ - &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */ - &isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (Mode Config) */ - NULL, /* 15 */ - NULL, /* 16 */ - NULL, /* 17 */ - NULL, /* 18 */ - NULL, /* 19 */ - &isakmp_nat_d, /* 20=130 ISAKMP_NEXT_NATD (NAT-D) */ - &isakmp_nat_oa, /* 20=131 ISAKMP_NEXT_NATOA (NAT-OA) */ -}; - -void -init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name) -{ - pbs->container = NULL; - pbs->desc = NULL; - pbs->name = name; - pbs->start = pbs->cur = start; - pbs->roof = start + len; - pbs->lenfld = NULL; - pbs->lenfld_desc = NULL; -} - -#ifdef DEBUG - -/* print a host struct - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - */ -void -DBG_print_struct(const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - bool immediate = FALSE; - const u_int8_t *inp = struct_ptr; - field_desc *fp; - - DBG_log("%s%s:", label, sd->name); - - for (fp = sd->fields; fp->field_type != ft_end; fp++) - { - int i = fp->size; - u_int32_t n = 0; - - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (!immediate && !len_meaningful) - break; - /* FALL THROUGH */ - case ft_nat: /* natural number (may be 0) */ - DBG_log(" %s: %lu", fp->name, (unsigned long)n); - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n)); - break; - case ft_set: /* bits representing set */ - DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n)); - break; - default: - bad_case(fp->field_type); - } - inp += i; - break; - - case ft_raw: /* bytes to be left in network-order */ - { - char m[50]; /* arbitrary limit on name width in log */ - - snprintf(m, sizeof(m), " %s:", fp->name); - DBG_dump(m, inp, i); - inp += i; - } - break; - default: - bad_case(fp->field_type); - } - } -} - -static void -DBG_prefix_print_struct(const pb_stream *pbs -, const char *label, const void *struct_ptr -, struct_desc *sd, bool len_meaningful) -{ - /* print out a title, with a prefix of asterisks to show - * the nesting level. - */ - char space[40]; /* arbitrary limit on label+flock-of-* */ - size_t len = strlen(label); - - if (sizeof(space) <= len) - { - DBG_print_struct(label, struct_ptr, sd, len_meaningful); - } - else - { - const pb_stream *p = pbs; - char *pre = &space[sizeof(space) - (len + 1)]; - - strcpy(pre, label); - - /* put at least one * out */ - for (;;) - { - if (pre <= space) - break; - *--pre = '*'; - if (p == NULL) - break; - p = p->container; - } - DBG_print_struct(pre, struct_ptr, sd, len_meaningful); - } -} - -#endif - -/* "parse" a network struct into a host struct. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is supplied, a new pb_stream is created for the - * variable part of the structure (this depends on their - * being one length field in the structure). The cursor of this - * new PBS is set to after the parsed part of the struct. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -in_struct(void *struct_ptr, struct_desc *sd -, pb_stream *ins, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - u_int8_t *cur = ins->cur; - - if (ins->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room in input packet for %s", sd->name); - } - else - { - u_int8_t *roof = cur + sd->size; /* may be changed by a length field */ - u_int8_t *outp = struct_ptr; - bool immediate = FALSE; - field_desc *fp; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(ins->roof - cur >= (ptrdiff_t)i); - passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i)); - passert(outp - (cur - ins->cur) == struct_ptr); - -#if 0 - DBG(DBG_PARSING, DBG_log("%d %s" - , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name)); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - for (; i != 0; i--) - { - if (*cur++ != 0) - { - ugh = builddiag("byte %d of %s must be zero, but is not" - , (int) (cur - ins->cur), sd->name); - break; - } - *outp++ = '\0'; /* probably redundant */ - } - break; - - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - for (; i != 0; i--) - n = (n << BITS_PER_BYTE) | *cur++; - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - { - u_int32_t len = fp->field_type == ft_len? n - : immediate? sd->size : n + sd->size; - - if (len < sd->size) - { - ugh = builddiag("%s of %s is smaller than minimum" - , fp->name, sd->name); - } - else if (pbs_left(ins) < len) - { - ugh = builddiag("%s of %s is larger than can fit" - , fp->name, sd->name); - } - else - { - roof = ins->cur + len; - } - break; - } - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - i = fp->size; - switch (i) - { - case 8/BITS_PER_BYTE: - *(u_int8_t *)outp = n; - break; - case 16/BITS_PER_BYTE: - *(u_int16_t *)outp = n; - break; - case 32/BITS_PER_BYTE: - *(u_int32_t *)outp = n; - break; - default: - bad_case(i); - } - outp += i; - break; - } - - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - { - *outp++ = *cur++; - } - break; - - case ft_end: /* end of field list */ - passert(cur == ins->cur + sd->size); - if (obj_pbs != NULL) - { - init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name); - obj_pbs->container = ins; - obj_pbs->desc = sd; - obj_pbs->cur = cur; - } - ins->cur = roof; - DBG(DBG_PARSING - , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE)); - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); - return FALSE; -} - -bool -in_raw(void *bytes, size_t len, pb_stream *ins, const char *name) -{ - if (pbs_left(ins) < len) - { - loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name); - return FALSE; - } - else - { - if (bytes == NULL) - { - DBG(DBG_PARSING - , DBG_log("skipping %u raw bytes of %s (%s)" - , (unsigned) len, ins->name, name); - DBG_dump(name, ins->cur, len)); - } - else - { - memcpy(bytes, ins->cur, len); - DBG(DBG_PARSING - , DBG_log("parsing %u raw bytes of %s into %s" - , (unsigned) len, ins->name, name); - DBG_dump(name, bytes, len)); - } - ins->cur += len; - return TRUE; - } -} - -/* "emit" a host struct into a network packet. - * - * This code assumes that the network and host structure - * members have the same alignment and size! This requires - * that all padding be explicit. - * - * If obj_pbs is non-NULL, its pbs describes a new output stream set up - * to contain the object. The cursor will be left at the variable part. - * This new stream must subsequently be finalized by close_output_pbs(). - * - * The value of any field of type ft_len is computed, not taken - * from the input struct. The length is actually filled in when - * the object's output stream is finalized. If obj_pbs is NULL, - * finalization is done by out_struct before it returns. - * - * This routine returns TRUE iff it succeeds. - */ - -bool -out_struct(const void *struct_ptr, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - err_t ugh = NULL; - const u_int8_t *inp = struct_ptr; - u_int8_t *cur = outs->cur; - - DBG(DBG_EMITTING - , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL)); - - if (outs->roof - cur < (ptrdiff_t)sd->size) - { - ugh = builddiag("not enough room left in output packet to place %s" - , sd->name); - } - else - { - bool immediate = FALSE; - pb_stream obj; - field_desc *fp; - - obj.lenfld = NULL; /* until a length field is discovered */ - obj.lenfld_desc = NULL; - - for (fp = sd->fields; ugh == NULL; fp++) - { - size_t i = fp->size; - - passert(outs->roof - cur >= (ptrdiff_t)i); - passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i)); - passert(inp - (cur - outs->cur) == struct_ptr); - -#if 0 - DBG(DBG_EMITTING, DBG_log("%d %s" - , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name); -#endif - switch (fp->field_type) - { - case ft_mbz: /* must be zero */ - inp += i; - for (; i != 0; i--) - *cur++ = '\0'; - break; - case ft_nat: /* natural number (may be 0) */ - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - case ft_enum: /* value from an enumeration */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - case ft_af_enum: /* Attribute Format + value from an enumeration */ - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - case ft_set: /* bits representing set */ - { - u_int32_t n = 0; - - switch (i) - { - case 8/BITS_PER_BYTE: - n = *(const u_int8_t *)inp; - break; - case 16/BITS_PER_BYTE: - n = *(const u_int16_t *)inp; - break; - case 32/BITS_PER_BYTE: - n = *(const u_int32_t *)inp; - break; - default: - bad_case(i); - } - - switch (fp->field_type) - { - case ft_len: /* length of this struct and any following crud */ - case ft_lv: /* length/value field of attribute */ - if (immediate) - break; /* not a length */ - /* We can't check the length because it will likely - * be filled in after variable part is supplied. - * We do record where this is so that it can be - * filled in by a subsequent close_output_pbs(). - */ - passert(obj.lenfld == NULL); /* only one ft_len allowed */ - obj.lenfld = cur; - obj.lenfld_desc = fp; - break; - case ft_af_loose_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - break; - case ft_af_enum: /* Attribute Format + value from an enumeration */ - if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) - immediate = TRUE; - /* FALL THROUGH */ - case ft_enum: /* value from an enumeration */ - if (enum_name(fp->desc, n) == NULL) - { - ugh = builddiag("%s of %s has an unknown value: %lu" - , fp->name, sd->name, (unsigned long)n); - } - /* FALL THROUGH */ - case ft_loose_enum: /* value from an enumeration with only some names known */ - break; - case ft_set: /* bits representing set */ - if (!testset(fp->desc, n)) - { - ugh = builddiag("bitset %s of %s has unknown member(s): %s" - , fp->name, sd->name, bitnamesof(fp->desc, n)); - } - break; - default: - break; - } - - while (i-- != 0) - { - cur[i] = (u_int8_t)n; - n >>= BITS_PER_BYTE; - } - inp += fp->size; - cur += fp->size; - break; - } - case ft_raw: /* bytes to be left in network-order */ - for (; i != 0; i--) - *cur++ = *inp++; - break; - case ft_end: /* end of field list */ - passert(cur == outs->cur + sd->size); - - obj.container = outs; - obj.desc = sd; - obj.name = sd->name; - obj.start = outs->cur; - obj.cur = cur; - obj.roof = outs->roof; /* limit of possible */ - /* obj.lenfld and obj.lenfld_desc already set */ - - if (obj_pbs == NULL) - { - close_output_pbs(&obj); /* fill in length field, if any */ - } - else - { - /* We set outs->cur to outs->roof so that - * any attempt to output something into outs - * before obj is closed will trigger an error. - */ - outs->cur = outs->roof; - - *obj_pbs = obj; - } - return TRUE; - - default: - bad_case(fp->field_type); - } - } - } - - /* some failure got us here: report it */ - loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */ - return FALSE; -} - -bool -out_generic(u_int8_t np, struct_desc *sd -, pb_stream *outs, pb_stream *obj_pbs) -{ - struct isakmp_generic gen; - - passert(sd->fields == isakmp_generic_desc.fields); - gen.isag_np = np; - return out_struct(&gen, sd, outs, obj_pbs); -} - -bool -out_generic_raw(u_int8_t np, struct_desc *sd -, pb_stream *outs, const void *bytes, size_t len, const char *name) -{ - pb_stream pbs; - - if (!out_generic(np, sd, outs, &pbs) - || !out_raw(bytes, len, &pbs, name)) - return FALSE; - close_output_pbs(&pbs); - return TRUE; -} - -bool -out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s" - , (unsigned long) len, name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING - , DBG_log("emitting %u raw bytes of %s into %s" - , (unsigned) len, name, outs->name); - DBG_dump(name, bytes, len)); - memcpy(outs->cur, bytes, len); - outs->cur += len; - return TRUE; - } -} - -bool -out_zero(size_t len, pb_stream *outs, const char *name) -{ - if (pbs_left(outs) < len) - { - loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name); - return FALSE; - } - else - { - DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s" - , (unsigned) len, name, outs->name)); - memset(outs->cur, 0x00, len); - outs->cur += len; - return TRUE; - } -} - -/* Record current length. - * Note: currently, this may be repeated any number of times; - * the last one wins. - */ -void -close_output_pbs(pb_stream *pbs) -{ - if (pbs->lenfld != NULL) - { - u_int32_t len = pbs_offset(pbs); - int i = pbs->lenfld_desc->size; - - if (pbs->lenfld_desc->field_type == ft_lv) - len -= sizeof(struct isakmp_attribute); - DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu" - , pbs->name, (unsigned long) len)); - while (i-- != 0) - { - pbs->lenfld[i] = (u_int8_t)len; - len >>= BITS_PER_BYTE; - } - } - if (pbs->container != NULL) - pbs->container->cur = pbs->cur; /* pass space utilization up */ -} diff --git a/src/pluto/packet.h b/src/pluto/packet.h deleted file mode 100644 index 1510b81a0..000000000 --- a/src/pluto/packet.h +++ /dev/null @@ -1,653 +0,0 @@ -/* parsing packets: formats and tools - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PACKET_H -#define _PACKET_H - -/* a struct_desc describes a structure for the struct I/O routines. - * This requires arrays of field_desc values to describe struct fields. - */ - -typedef const struct struct_desc { - const char *name; - const struct field_desc *fields; - size_t size; -} struct_desc; - -/* Note: if an ft_af_enum field has the ISAKMP_ATTR_AF_TV bit set, - * the subsequent ft_lv field will be interpreted as an immediate value. - * This matches how attributes are encoded. - * See RFC 2408 "ISAKMP" 3.3 - */ - -enum field_type { - ft_mbz, /* must be zero */ - ft_nat, /* natural number (may be 0) */ - ft_len, /* length of this struct and any following crud */ - ft_lv, /* length/value field of attribute */ - ft_enum, /* value from an enumeration */ - ft_loose_enum, /* value from an enumeration with only some names known */ - ft_af_loose_enum, /* Attribute Format + enumeration, some names known */ - ft_af_enum, /* Attribute Format + value from an enumeration */ - ft_set, /* bits representing set */ - ft_raw, /* bytes to be left in network-order */ - ft_end, /* end of field list */ -}; - -typedef const struct field_desc { - enum field_type field_type; - int size; /* size, in bytes, of field */ - const char *name; - const void *desc; /* enum_names for enum or char *[] for bits */ -} field_desc; - -/* The formatting of input and output of packets is done - * through packet_byte_stream objects. - * These describe a stream of bytes in memory. - * Several routines are provided to manipulate these objects - * Actual packet transfer is done elsewhere. - */ -typedef struct packet_byte_stream { - struct packet_byte_stream *container; /* PBS of which we are part */ - struct_desc *desc; - const char *name; /* what does this PBS represent? */ - u_int8_t - *start, - *cur, /* current position in stream */ - *roof; /* byte after last in PBS (actually just a limit on output) */ - /* For an output PBS, the length field will be filled in later so - * we need to record its particulars. Note: it may not be aligned. - */ - u_int8_t *lenfld; - field_desc *lenfld_desc; -} pb_stream; - -/* For an input PBS, pbs_offset is amount of stream processed. - * For an output PBS, pbs_offset is current size of stream. - * For an input PBS, pbs_room is size of stream. - * For an output PBS, pbs_room is maximum size allowed. - */ -#define pbs_offset(pbs) ((size_t)((pbs)->cur - (pbs)->start)) -#define pbs_room(pbs) ((size_t)((pbs)->roof - (pbs)->start)) -#define pbs_left(pbs) ((size_t)((pbs)->roof - (pbs)->cur)) - -extern void init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name); - -extern bool in_struct(void *struct_ptr, struct_desc *sd, - pb_stream *ins, pb_stream *obj_pbs); -extern bool in_raw(void *bytes, size_t len, pb_stream *ins, const char *name); - -extern bool out_struct(const void *struct_ptr, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic(u_int8_t np, struct_desc *sd, - pb_stream *outs, pb_stream *obj_pbs); -extern bool out_generic_raw(u_int8_t np, struct_desc *sd, - pb_stream *outs, const void *bytes, size_t len, const char *name); -#define out_generic_chunk(np, sd, outs, ch, name) \ - out_generic_raw(np, sd, outs, (ch).ptr, (ch).len, name) -extern bool out_zero(size_t len, pb_stream *outs, const char *name); -extern bool out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name); -#define out_chunk(ch, outs, name) out_raw((ch).ptr, (ch).len, (outs), (name)) -extern void close_output_pbs(pb_stream *pbs); - -#ifdef DEBUG -extern void DBG_print_struct(const char *label, const void *struct_ptr, - struct_desc *sd, bool len_meaningful); -#endif - -/* ISAKMP Header: for all messages - * layout from RFC 2408 "ISAKMP" section 3.1 - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Initiator ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Responder ! - * ! Cookie ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Message ID ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * Although the drafts are a little unclear, there are a few - * places that specify that messages should be padded with 0x00 - * octets (bytes) to make the length a multiple of something. - * - * RFC 2408 "ISAKMP" 3.6 specifies that all messages will be - * padded to be a multiple of 4 octets in length. - * ??? This looks vestigial, and we ignore this requirement. - * - * RFC 2409 "IKE" Appedix B specifies: - * Each message should be padded up to the nearest block size - * using bytes containing 0x00. - * ??? This does not appear to be limited to encrypted messages, - * but it surely must be: the block size is meant to be the encryption - * block size, and that is meaningless for a non-encrypted message. - * - * RFC 2409 "IKE" 5.3 specifies: - * Encrypted payloads are padded up to the nearest block size. - * All padding bytes, except for the last one, contain 0x00. The - * last byte of the padding contains the number of the padding - * bytes used, excluding the last one. Note that this means there - * will always be padding. - * ??? This is nuts since payloads are not padded, messages are. - * It also contradicts Appendix B. So we ignore it. - * - * Summary: we pad encrypted output messages with 0x00 to bring them - * up to a multiple of the encryption block size. On input, we require - * that any encrypted portion of a message be a multiple of the encryption - * block size. After any decryption, we ignore padding (any bytes after - * the first payload that specifies a next payload of none; we don't - * require them to be zero). - */ - -struct isakmp_hdr -{ - u_int8_t isa_icookie[COOKIE_SIZE]; - u_int8_t isa_rcookie[COOKIE_SIZE]; - u_int8_t isa_np; /* Next payload */ - u_int8_t isa_version; /* high-order 4 bits: Major; low order 4: Minor */ -#define ISA_MAJ_SHIFT 4 -#define ISA_MIN_MASK (~((~0u) << ISA_MAJ_SHIFT)) - u_int8_t isa_xchg; /* Exchange type */ - u_int8_t isa_flags; - u_int32_t isa_msgid; /* Message ID (RAW) */ - u_int32_t isa_length; /* Length of message */ -}; - -extern struct_desc isakmp_hdr_desc; - -/* Generic portion of all ISAKMP payloads. - * layout from RFC 2408 "ISAKMP" section 3.2 - * This describes the first 32-bit chunk of all payloads. - * The previous next payload depends on the actual payload type. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_generic -{ - u_int8_t isag_np; - u_int8_t isag_reserved; - u_int16_t isag_length; -}; - -extern struct_desc isakmp_generic_desc; - -/* ISAKMP Data Attribute (generic representation within payloads) - * layout from RFC 2408 "ISAKMP" section 3.3 - * This is not a payload type. - * In TLV format, this is followed by a value field. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * !A! Attribute Type ! AF=0 Attribute Length ! - * !F! ! AF=1 Attribute Value ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . AF=0 Attribute Value . - * . AF=1 Not Transmitted . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_attribute -{ - /* The high order bit of isaat_af_type is the Attribute Format - * If it is off, the format is TLV: lv is the length of the following - * attribute value. - * If it is on, the format is TV: lv is the value of the attribute. - * ISAKMP_ATTR_AF_MASK is the mask in host form. - * - * The low order 15 bits of isaat_af_type is the Attribute Type. - * ISAKMP_ATTR_RTYPE_MASK is the mask in host form. - */ - u_int16_t isaat_af_type; /* high order bit: AF; lower 15: rtype */ - u_int16_t isaat_lv; /* Length or value */ -}; - -#define ISAKMP_ATTR_AF_MASK 0x8000 -#define ISAKMP_ATTR_AF_TV ISAKMP_ATTR_AF_MASK /* value in lv */ -#define ISAKMP_ATTR_AF_TLV 0 /* length in lv; value follows */ - -#define ISAKMP_ATTR_RTYPE_MASK 0x7FFF - -extern struct_desc - isakmp_oakley_attribute_desc, - isakmp_ipsec_attribute_desc; - -/* ISAKMP Security Association Payload - * layout from RFC 2408 "ISAKMP" section 3.4 - * A variable length Situation follows. - * Previous next payload: ISAKMP_NEXT_SA - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Situation ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_sa -{ - u_int8_t isasa_np; /* Next payload */ - u_int8_t isasa_reserved; - u_int16_t isasa_length; /* Payload length */ - u_int32_t isasa_doi; /* DOI */ -}; - -extern struct_desc isakmp_sa_desc; - -extern struct_desc ipsec_sit_desc; - -/* ISAKMP Proposal Payload - * layout from RFC 2408 "ISAKMP" section 3.5 - * A variable length SPI follows. - * Previous next payload: ISAKMP_NEXT_P - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! SPI (variable) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_proposal -{ - u_int8_t isap_np; - u_int8_t isap_reserved; - u_int16_t isap_length; - u_int8_t isap_proposal; - u_int8_t isap_protoid; - u_int8_t isap_spisize; - u_int8_t isap_notrans; /* Number of transforms */ -}; - -extern struct_desc isakmp_proposal_desc; - -/* ISAKMP Transform Payload - * layout from RFC 2408 "ISAKMP" section 3.6 - * Variable length SA Attributes follow. - * Previous next payload: ISAKMP_NEXT_T - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Transform # ! Transform-Id ! RESERVED2 ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ SA Attributes ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_transform -{ - u_int8_t isat_np; - u_int8_t isat_reserved; - u_int16_t isat_length; - u_int8_t isat_transnum; /* Number of the transform */ - u_int8_t isat_transid; - u_int16_t isat_reserved2; -}; - -extern struct_desc - isakmp_isakmp_transform_desc, - isakmp_ah_transform_desc, - isakmp_esp_transform_desc, - isakmp_ipcomp_transform_desc; - -/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.7 - * Variable Key Exchange Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_KE - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Key Exchange Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_keyex_desc; - -/* ISAKMP Identification Payload - * layout from RFC 2408 "ISAKMP" section 3.8 - * See "struct identity" declared later. - * Variable length Identification Data follow. - * Previous next payload: ISAKMP_NEXT_ID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! DOI Specific ID Data ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Identification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_id -{ - u_int8_t isaid_np; - u_int8_t isaid_reserved; - u_int16_t isaid_length; - u_int8_t isaid_idtype; - u_int8_t isaid_doi_specific_a; - u_int16_t isaid_doi_specific_b; -}; - -extern struct_desc isakmp_identification_desc; - -/* IPSEC Identification Payload Content - * layout from RFC 2407 "IPsec DOI" section 4.6.2 - * See struct isakmp_id declared earlier. - * Note: Hashing skips the ISAKMP generic payload header - * Variable length Identification Data follow. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ID Type ! Protocol ID ! Port ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ~ Identification Data ~ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_ipsec_id -{ - u_int8_t isaiid_np; - u_int8_t isaiid_reserved; - u_int16_t isaiid_length; - u_int8_t isaiid_idtype; - u_int8_t isaiid_protoid; - u_int16_t isaiid_port; -}; - -extern struct_desc isakmp_ipsec_identification_desc; - -/* ISAKMP Certificate Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.9 - * Variable length Certificate Data follow the generic fields. - * Previous next payload: ISAKMP_NEXT_CERT. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert Encoding ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cert -{ - u_int8_t isacert_np; - u_int8_t isacert_reserved; - u_int16_t isacert_length; - u_int8_t isacert_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cert) - * yields the wrong value for the length. - */ -#define ISAKMP_CERT_SIZE 5 - -extern struct_desc isakmp_ipsec_certificate_desc; - -/* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.10 - * Variable length Certificate Types and Certificate Authorities follow. - * Previous next payload: ISAKMP_NEXT_CR. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Cert. Type ! ! - * +-+-+-+-+-+-+-+-+ ! - * ~ Certificate Authority ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_cr -{ - u_int8_t isacr_np; - u_int8_t isacr_reserved; - u_int16_t isacr_length; - u_int8_t isacr_type; -}; - -/* NOTE: this packet type has a fixed portion that is not a - * multiple of 4 octets. This means that sizeof(struct isakmp_cr) - * yields the wrong value for the length. - */ -#define ISAKMP_CR_SIZE 5 - -extern struct_desc isakmp_ipsec_cert_req_desc; - -/* ISAKMP Hash Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.11 - * Variable length Hash Data follow. - * Previous next payload: ISAKMP_NEXT_HASH. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Hash Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_hash_desc; - -/* ISAKMP Signature Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.12 - * Variable length Signature Data follow. - * Previous next payload: ISAKMP_NEXT_SIG. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Signature Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_signature_desc; - -/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones. - * layout from RFC 2408 "ISAKMP" section 3.13 - * Variable length Nonce Data follow. - * Previous next payload: ISAKMP_NEXT_NONCE. - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Nonce Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_nonce_desc; - -/* ISAKMP Notification Payload - * layout from RFC 2408 "ISAKMP" section 3.14 - * This is followed by a variable length SPI - * and then possibly by variable length Notification Data. - * Previous next payload: ISAKMP_NEXT_N - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-ID ! SPI Size ! Notify Message Type ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Notification Data ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_notification -{ - u_int8_t isan_np; - u_int8_t isan_reserved; - u_int16_t isan_length; - u_int32_t isan_doi; - u_int8_t isan_protoid; - u_int8_t isan_spisize; - u_int16_t isan_type; -}; - -extern struct_desc isakmp_notification_desc; - -/* ISAKMP Delete Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length SPI. - * Previous next payload: ISAKMP_NEXT_D - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Domain of Interpretation (DOI) ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Protocol-Id ! SPI Size ! # of SPIs ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Security Parameter Index(es) (SPI) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -struct isakmp_delete -{ - u_int8_t isad_np; - u_int8_t isad_reserved; - u_int16_t isad_length; - u_int32_t isad_doi; - u_int8_t isad_protoid; - u_int8_t isad_spisize; - u_int16_t isad_nospi; -}; - -extern struct_desc isakmp_delete_desc; - -/* From draft-dukes-ike-mode-cfg -3.2. Attribute Payload - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ! ! - ~ Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ -struct isakmp_mode_attr -{ - u_int8_t isama_np; - u_int8_t isama_reserved; - u_int16_t isama_length; - u_int8_t isama_type; - u_int8_t isama_reserved2; - u_int16_t isama_identifier; -}; - -extern struct_desc isakmp_attr_desc; -extern struct_desc isakmp_modecfg_attribute_desc; - -/* ISAKMP Vendor ID Payload - * layout from RFC 2408 "ISAKMP" section 3.15 - * This is followed by a variable length VID. - * Previous next payload: ISAKMP_NEXT_VID - * 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! Next Payload ! RESERVED ! Payload Length ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * ! ! - * ~ Vendor ID (VID) ~ - * ! ! - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -extern struct_desc isakmp_vendor_id_desc; - -struct isakmp_nat_oa -{ - u_int8_t isanoa_np; - u_int8_t isanoa_reserved_1; - u_int16_t isanoa_length; - u_int8_t isanoa_idtype; - u_int8_t isanoa_reserved_2; - u_int16_t isanoa_reserved_3; -}; - -extern struct_desc isakmp_nat_d; -extern struct_desc isakmp_nat_oa; - -/* union of all payloads */ - -union payload { - struct isakmp_generic generic; - struct isakmp_sa sa; - struct isakmp_proposal proposal; - struct isakmp_transform transform; - struct isakmp_id id; /* Main Mode */ - struct isakmp_cert cert; - struct isakmp_cr cr; - struct isakmp_ipsec_id ipsec_id; /* Quick Mode */ - struct isakmp_notification notification; - struct isakmp_delete delete; - struct isakmp_nat_oa nat_oa; - struct isakmp_mode_attr attribute; -}; - -/* descriptor for each payload type - * - * There is a slight problem in that some payloads differ, depending - * on the mode. Since this is table only used for top-level payloads, - * Proposal and Transform payloads need not be handled. - * That leaves only Identification payloads as a problem. - * We make all these entries NULL - */ -extern struct_desc *const payload_descs[ISAKMP_NEXT_ROOF]; - -#endif /* _PACKET_H */ diff --git a/src/pluto/pkcs7.c b/src/pluto/pkcs7.c deleted file mode 100644 index 10b2a4d5a..000000000 --- a/src/pluto/pkcs7.c +++ /dev/null @@ -1,755 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * HSR Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pkcs7.h" - -const contentInfo_t empty_contentInfo = { - OID_UNKNOWN , /* type */ - { NULL, 0 } /* content */ -}; - -/** - * ASN.1 definition of the PKCS#7 ContentInfo type - */ -static const asn1Object_t contentInfoObjects[] = { - { 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */ - { 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_INFO_TYPE 1 -#define PKCS7_INFO_CONTENT 2 - -/** - * ASN.1 definition of the PKCS#7 signedData type - */ -static const asn1Object_t signedDataObjects[] = { - { 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */ - { 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */ - { 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_LOOP }, /* 6 */ - { 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */ - { 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_LOOP }, /* 9 */ - { 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */ - { 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */ - { 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */ - { 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */ - { 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */ - { 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_OBJ }, /* 19 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */ - { 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */ - { 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */ - { 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */ - { 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_SIGNED_VERSION 1 -#define PKCS7_DIGEST_ALG 3 -#define PKCS7_SIGNED_CONTENT_INFO 5 -#define PKCS7_SIGNED_CERT 7 -#define PKCS7_SIGNER_INFO 13 -#define PKCS7_SIGNER_INFO_VERSION 14 -#define PKCS7_SIGNED_ISSUER 16 -#define PKCS7_SIGNED_SERIAL_NUMBER 17 -#define PKCS7_DIGEST_ALGORITHM 18 -#define PKCS7_AUTH_ATTRIBUTES 19 -#define PKCS7_DIGEST_ENC_ALGORITHM 21 -#define PKCS7_ENCRYPTED_DIGEST 22 - -/** - * ASN.1 definition of the PKCS#7 envelopedData type - */ -static const asn1Object_t envelopedDataObjects[] = { - { 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ - { 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */ - { 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */ - { 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */ - { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */ - { 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */ - { 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */ - { 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */ - { 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */ - { 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */ - { 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */ - { 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */ - { 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */ - { 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */ - { 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } -}; -#define PKCS7_ENVELOPED_VERSION 1 -#define PKCS7_RECIPIENT_INFO_VERSION 4 -#define PKCS7_ISSUER 6 -#define PKCS7_SERIAL_NUMBER 7 -#define PKCS7_ENCRYPTION_ALG 8 -#define PKCS7_ENCRYPTED_KEY 9 -#define PKCS7_CONTENT_TYPE 12 -#define PKCS7_CONTENT_ENC_ALGORITHM 13 -#define PKCS7_ENCRYPTED_CONTENT 14 -#define PKCS7_ENVELOPED_ROOF 15 - -/** - * Parse PKCS#7 ContentInfo object - */ -bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo) -{ - asn1_parser_t *parser; - chunk_t object; - int objectID; - bool success = FALSE; - - parser = asn1_parser_create(contentInfoObjects, blob); - parser->set_top_level(parser, level0); - - while (parser->iterate(parser, &objectID, &object)) - { - if (objectID == PKCS7_INFO_TYPE) - { - cInfo->type = asn1_known_oid(object); - if (cInfo->type < OID_PKCS7_DATA - || cInfo->type > OID_PKCS7_ENCRYPTED_DATA) - { - DBG1(DBG_LIB, "unknown pkcs7 content type"); - goto end; - } - } - else if (objectID == PKCS7_INFO_CONTENT) - { - cInfo->content = object; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - return success; -} - -/** - * Parse a PKCS#7 signedData object - */ -bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *certs, - chunk_t *attributes, certificate_t *cacert) -{ - asn1_parser_t *parser; - chunk_t object; - int digest_alg = OID_UNKNOWN; - int enc_alg = OID_UNKNOWN; - int signerInfos = 0; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - chunk_t encrypted_digest = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - return FALSE; - } - if (cInfo.type != OID_PKCS7_SIGNED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not signedData"); - return FALSE; - } - - parser = asn1_parser_create(signedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_SIGNED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_DIGEST_ALG: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_SIGNED_CONTENT_INFO: - if (data != NULL) - { - pkcs7_parse_contentInfo(object, level, data); - } - break; - case PKCS7_SIGNED_CERT: - { - certificate_t *cert; - - DBG2(DBG_LIB, " parsing pkcs7-wrapped certificate"); - cert = lib->creds->create(lib->creds, - CRED_CERTIFICATE, CERT_X509, - BUILD_BLOB_ASN1_DER, object, - BUILD_END); - if (cert) - { - certs->insert_last(certs, cert); - } - } - break; - case PKCS7_SIGNER_INFO: - signerInfos++; - DBG2(DBG_LIB, " signer #%d", signerInfos); - break; - case PKCS7_SIGNER_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - break; - case PKCS7_SIGNED_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_AUTH_ATTRIBUTES: - if (attributes != NULL) - { - *attributes = object; - *attributes->ptr = ASN1_SET; - } - break; - case PKCS7_DIGEST_ALGORITHM: - digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_DIGEST_ENC_ALGORITHM: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - break; - case PKCS7_ENCRYPTED_DIGEST: - encrypted_digest = object; - } - } - success = parser->success(parser); - parser->destroy(parser); - if (!success) - { - return FALSE; - } - - /* check the signature only if a cacert is available */ - if (cacert != NULL) - { - public_key_t *key; - signature_scheme_t scheme; - - scheme = signature_scheme_from_oid(digest_alg); - if (scheme == SIGN_UNKNOWN) - { - DBG1(DBG_LIB, "unsupported signature scheme"); - return FALSE; - } - if (signerInfos == 0) - { - DBG1(DBG_LIB, "no signerInfo object found"); - return FALSE; - } - else if (signerInfos > 1) - { - DBG1(DBG_LIB, "more than one signerInfo object found"); - return FALSE; - } - if (attributes->ptr == NULL) - { - DBG1(DBG_LIB, "no authenticatedAttributes object found"); - return FALSE; - } - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only RSA digest encryption supported"); - return FALSE; - } - - /* verify the signature */ - key = cacert->get_public_key(cacert); - if (key == NULL) - { - DBG1(DBG_LIB, "no public key found in CA certificate"); - return FALSE; - } - if (key->verify(key, scheme, *attributes, encrypted_digest)) - { - DBG2(DBG_LIB, "signature is valid"); - } - else - { - DBG1(DBG_LIB, "invalid signature"); - success = FALSE; - } - key->destroy(key); - } - return success; -} - -/** - * Parse a PKCS#7 envelopedData object - */ -bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, - private_key_t *key) -{ - asn1_parser_t *parser; - chunk_t object; - chunk_t iv = chunk_empty; - chunk_t symmetric_key = chunk_empty; - chunk_t encrypted_content = chunk_empty; - - crypter_t *crypter = NULL; - - int enc_alg = OID_UNKNOWN; - int content_enc_alg = OID_UNKNOWN; - int version; - int objectID; - bool success = FALSE; - - contentInfo_t cInfo = empty_contentInfo; - *data = chunk_empty; - - if (!pkcs7_parse_contentInfo(blob, 0, &cInfo)) - { - goto failed; - } - if (cInfo.type != OID_PKCS7_ENVELOPED_DATA) - { - DBG1(DBG_LIB, "pkcs7 content type is not envelopedData"); - goto failed; - } - - parser = asn1_parser_create(envelopedDataObjects, cInfo.content); - parser->set_top_level(parser, 2); - - while (parser->iterate(parser, &objectID, &object)) - { - u_int level = parser->get_level(parser); - - switch (objectID) - { - case PKCS7_ENVELOPED_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "envelopedData version is not 0"); - goto end; - } - break; - case PKCS7_RECIPIENT_INFO_VERSION: - version = object.len ? (int)*object.ptr : 0; - DBG2(DBG_LIB, " v%d", version); - if (version != 0) - { - DBG1(DBG_LIB, "recipient info version is not 0"); - goto end; - } - break; - case PKCS7_ISSUER: - { - identification_t *issuer = identification_create_from_encoding( - ID_DER_ASN1_DN, object); - DBG2(DBG_LIB, " \"%Y\"", issuer); - issuer->destroy(issuer); - break; - } - case PKCS7_SERIAL_NUMBER: - if (!chunk_equals(serialNumber, object)) - { - DBG1(DBG_LIB, "serial numbers do not match"); - goto end; - } - break; - case PKCS7_ENCRYPTION_ALG: - enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL); - if (enc_alg != OID_RSA_ENCRYPTION) - { - DBG1(DBG_LIB, "only rsa encryption supported"); - goto end; - } - break; - case PKCS7_ENCRYPTED_KEY: - if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key)) - { - DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa"); - goto end; - } - DBG4(DBG_LIB, "symmetric key %B", &symmetric_key); - break; - case PKCS7_CONTENT_TYPE: - if (asn1_known_oid(object) != OID_PKCS7_DATA) - { - DBG1(DBG_LIB, "encrypted content not of type pkcs7 data"); - goto end; - } - break; - case PKCS7_CONTENT_ENC_ALGORITHM: - content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv); - - if (content_enc_alg == OID_UNKNOWN) - { - DBG1(DBG_LIB, "unknown content encryption algorithm"); - goto end; - } - if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV")) - { - DBG1(DBG_LIB, "IV could not be parsed"); - goto end; - } - break; - case PKCS7_ENCRYPTED_CONTENT: - encrypted_content = object; - break; - } - } - success = parser->success(parser); - -end: - parser->destroy(parser); - if (!success) - { - goto failed; - } - success = FALSE; - - /* decrypt the content */ - { - encryption_algorithm_t alg; - size_t key_size; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(content_enc_alg, &key_size); - if (alg == ENCR_UNDEFINED) - { - DBG1(DBG_LIB, "unsupported content encryption algorithm"); - goto failed; - } - crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg); - goto failed; - } - if (symmetric_key.len != crypter->get_key_size(crypter)) - { - DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len); - goto failed; - } - if (iv.len != crypter->get_iv_size(crypter)) - { - DBG1(DBG_LIB, "IV length %d is wrong", iv.len); - goto failed; - } - crypter->set_key(crypter, symmetric_key); - crypter->decrypt(crypter, encrypted_content, iv, data); - DBG4(DBG_LIB, "decrypted content with padding: %B", data); - } - - /* remove the padding */ - { - u_char *pos = data->ptr + data->len - 1; - u_char pattern = *pos; - size_t padding = pattern; - - if (padding > data->len) - { - DBG1(DBG_LIB, "padding greater than data length"); - goto failed; - } - data->len -= padding; - - while (padding-- > 0) - { - if (*pos-- != pattern) - { - DBG1(DBG_LIB, "wrong padding pattern"); - goto failed; - } - } - } - success = TRUE; - -failed: - DESTROY_IF(crypter); - chunk_clear(&symmetric_key); - if (!success) - { - free(data->ptr); - } - return success; -} - -/** - * @brief Builds a contentType attribute - * - * @return ASN.1 encoded contentType attribute - */ -chunk_t pkcs7_contentType_attribute(void) -{ - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_CONTENT_TYPE), - asn1_wrap(ASN1_SET, "m", - asn1_build_known_oid(OID_PKCS7_DATA))); -} - -/** - * @brief Builds a messageDigest attribute - * - * - * @param[in] blob content to create digest of - * @param[in] digest_alg digest algorithm to be used - * @return ASN.1 encoded messageDigest attribute - * - */ -chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg) -{ - chunk_t digest; - hash_algorithm_t hash_alg; - hasher_t *hasher; - - hash_alg = hasher_algorithm_from_oid(digest_alg); - hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); - hasher->allocate_hash(hasher, content, &digest); - hasher->destroy(hasher); - - return asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(OID_PKCS9_MESSAGE_DIGEST), - asn1_wrap(ASN1_SET, "m", - asn1_wrap(ASN1_OCTET_STRING, "m", digest))); -} - -/** - * build a DER-encoded contentInfo object - */ -static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo) -{ - return (cInfo->content.ptr) ? - asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_build_known_oid(cInfo->type), - asn1_simple_object(ASN1_CONTEXT_C_0, cInfo->content)) : - asn1_build_known_oid(cInfo->type); -} - -/** - * build issuerAndSerialNumber object - */ -chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert) -{ - identification_t *issuer = cert->get_issuer(cert); - x509_t *x509 = (x509_t*)cert; - - return asn1_wrap(ASN1_SEQUENCE, "cm", - issuer->get_encoding(issuer), - asn1_integer("c", x509->get_serial(x509))); -} - -/** - * create a signed pkcs7 contentInfo object - */ -chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key) -{ - contentInfo_t pkcs7Data, signedData; - chunk_t authenticatedAttributes = chunk_empty; - chunk_t encryptedDigest = chunk_empty; - chunk_t signerInfo, cInfo, signature, encoding = chunk_empty;; - signature_scheme_t scheme = signature_scheme_from_oid(digest_alg); - - if (attributes.ptr) - { - if (key->sign(key, scheme, attributes, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - authenticatedAttributes = chunk_clone(attributes); - *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; - } - } - else if (data.ptr) - { - if (key->sign(key, scheme, data, &signature)) - { - encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); - } - } - signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" - , ASN1_INTEGER_1 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(digest_alg) - , authenticatedAttributes - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedDigest); - - pkcs7Data.type = OID_PKCS7_DATA; - pkcs7Data.content = (data.ptr == NULL)? chunk_empty - : asn1_simple_object(ASN1_OCTET_STRING, data); - - cert->get_encoding(cert, CERT_ASN1_DER, &encoding); - signedData.type = OID_PKCS7_SIGNED_DATA; - signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" - , ASN1_INTEGER_1 - , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) - , pkcs7_build_contentInfo(&pkcs7Data) - , asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding) - , asn1_wrap(ASN1_SET, "m", signerInfo)); - - cInfo = pkcs7_build_contentInfo(&signedData); - DBG3(DBG_LIB, "signedData %B", &cInfo); - - free(pkcs7Data.content.ptr); - free(signedData.content.ptr); - return cInfo; -} - -/** - * create a symmetrically encrypted pkcs7 contentInfo object - */ -chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg) -{ - encryption_algorithm_t alg; - size_t alg_key_size; - chunk_t symmetricKey, protectedKey, iv, in, out; - crypter_t *crypter; - - alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size); - crypter = lib->crypto->create_crypter(lib->crypto, alg, - alg_key_size/BITS_PER_BYTE); - if (crypter == NULL) - { - DBG1(DBG_LIB, "crypter for %N not available", encryption_algorithm_names, alg); - return chunk_empty; - } - - /* generate a true random symmetric encryption key and a pseudo-random iv */ - { - rng_t *rng; - - rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); - rng->allocate_bytes(rng, crypter->get_key_size(crypter), &symmetricKey); - DBG4(DBG_LIB, "symmetric encryption key %B", &symmetricKey); - rng->destroy(rng); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv); - DBG4(DBG_LIB, "initialization vector: %B", &iv); - rng->destroy(rng); - } - - /* pad the data to a multiple of the block size */ - { - size_t block_size = crypter->get_block_size(crypter); - size_t padding = block_size - data.len % block_size; - - in.len = data.len + padding; - in.ptr = malloc(in.len); - - DBG2(DBG_LIB, "padding %u bytes of data to multiple block size of %u bytes", - data.len, in.len); - - /* copy data */ - memcpy(in.ptr, data.ptr, data.len); - /* append padding */ - memset(in.ptr + data.len, padding, padding); - } - DBG3(DBG_LIB, "padded unencrypted data %B", &in); - - /* symmetric encryption of data object */ - crypter->set_key(crypter, symmetricKey); - crypter->encrypt(crypter, in, iv, &out); - crypter->destroy(crypter); - chunk_clear(&in); - DBG3(DBG_LIB, "encrypted data %B", &out); - - /* protect symmetric key by public key encryption */ - { - public_key_t *key = cert->get_public_key(cert); - - if (key == NULL) - { - DBG1(DBG_LIB, "public key not found in encryption certificate"); - chunk_clear(&symmetricKey); - chunk_free(&iv); - chunk_free(&out); - return chunk_empty; - } - key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey); - key->destroy(key); - } - - /* build pkcs7 enveloped data object */ - { - - chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm" - , asn1_build_known_oid(enc_alg) - , asn1_simple_object(ASN1_OCTET_STRING, iv)); - - chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm" - , asn1_build_known_oid(OID_PKCS7_DATA) - , contentEncryptionAlgorithm - , asn1_wrap(ASN1_CONTEXT_S_0, "m", out)); - - chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m" - , protectedKey); - - chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm" - , ASN1_INTEGER_0 - , pkcs7_build_issuerAndSerialNumber(cert) - , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) - , encryptedKey); - - chunk_t cInfo; - contentInfo_t envelopedData; - - envelopedData.type = OID_PKCS7_ENVELOPED_DATA; - envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm" - , ASN1_INTEGER_0 - , asn1_wrap(ASN1_SET, "m", recipientInfo) - , encryptedContentInfo); - - cInfo = pkcs7_build_contentInfo(&envelopedData); - DBG3(DBG_LIB, "envelopedData %B", &cInfo); - - chunk_free(&envelopedData.content); - chunk_free(&iv); - chunk_clear(&symmetricKey); - return cInfo; - } -} diff --git a/src/pluto/pkcs7.h b/src/pluto/pkcs7.h deleted file mode 100644 index 1743ea9c4..000000000 --- a/src/pluto/pkcs7.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Support of PKCS#7 data structures - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Copyright (C) 2002-2009 Andreas Steffen - * - * Hochschule fuer Technik Rapperswil, Switzerland - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PKCS7_H -#define _PKCS7_H - -#include -#include -#include -#include - -/* Access structure for a PKCS#7 ContentInfo object */ - -typedef struct contentInfo contentInfo_t; - -struct contentInfo { - int type; - chunk_t content; -}; - -extern const contentInfo_t empty_contentInfo; - -extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, - contentInfo_t *cInfo); -extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, - linked_list_t *cert, chunk_t *attributes, - certificate_t *cacert); -extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data, - chunk_t serialNumber, private_key_t *key); -extern chunk_t pkcs7_contentType_attribute(void); -extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg); -extern chunk_t pkcs7_build_issuerAndSerialNumber(certificate_t *cert); -extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, - certificate_t *cert, int digest_alg, - private_key_t *key); -extern chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, - int enc_alg); - -#endif /* _PKCS7_H */ diff --git a/src/pluto/plugin_list.c b/src/pluto/plugin_list.c deleted file mode 100644 index 499218904..000000000 --- a/src/pluto/plugin_list.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 Martin Willi, revosec AG - * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include - -#include -#include - -/** - * List loaded plugin information - */ -void plugin_list(void) -{ - plugin_feature_t *features, *fp; - enumerator_t *enumerator; - linked_list_t *list; - plugin_t *plugin; - int count, i; - bool loaded; - char *str; - - whack_log(RC_COMMENT, " "); - whack_log(RC_COMMENT, "List of loaded Plugins:"); - whack_log(RC_COMMENT, " "); - - enumerator = lib->plugins->create_plugin_enumerator(lib->plugins); - while (enumerator->enumerate(enumerator, &plugin, &list)) - { - whack_log(RC_COMMENT, "%s:", plugin->get_name(plugin)); - if (plugin->get_features) - { - count = plugin->get_features(plugin, &features); - for (i = 0; i < count; i++) - { - str = plugin_feature_get_string(&features[i]); - switch (features[i].kind) - { - case FEATURE_PROVIDE: - fp = &features[i]; - loaded = list->find_first(list, NULL, - (void**)&fp) == SUCCESS; - whack_log(RC_COMMENT, " %s%s", - str, loaded ? "" : " (not loaded)"); - break; - case FEATURE_DEPENDS: - whack_log(RC_COMMENT, " %s", str); - break; - case FEATURE_SDEPEND: - whack_log(RC_COMMENT, " %s(soft)", str); - break; - default: - break; - } - free(str); - } - } - } - enumerator->destroy(enumerator); -} diff --git a/src/pluto/plugin_list.h b/src/pluto/plugin_list.h deleted file mode 100644 index 62e4a167d..000000000 --- a/src/pluto/plugin_list.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Generates a list of all loaded plugins and their dependencies - * Copyright (C) 2011 Andreas Steffen - * HSR Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#ifndef _PLUGIN_LIST_H -#define _PLUGIN_LIST_H - -extern void plugin_list(void); - -#endif /* _PLUGIN_LIST_H */ diff --git a/src/pluto/plugins/xauth/Makefile.am b/src/pluto/plugins/xauth/Makefile.am deleted file mode 100644 index 354325b35..000000000 --- a/src/pluto/plugins/xauth/Makefile.am +++ /dev/null @@ -1,15 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/whack \ - -I$(top_srcdir)/src/pluto - -AM_CFLAGS = -rdynamic - -plugin_LTLIBRARIES = libstrongswan-xauth.la - -libstrongswan_xauth_la_SOURCES = \ - xauth_plugin.h xauth_plugin.c \ - xauth_default_provider.c xauth_default_provider.h \ - xauth_default_verifier.c xauth_default_verifier.h - -libstrongswan_xauth_la_LDFLAGS = -module -avoid-version diff --git a/src/pluto/plugins/xauth/Makefile.in b/src/pluto/plugins/xauth/Makefile.in deleted file mode 100644 index 5a575548e..000000000 --- a/src/pluto/plugins/xauth/Makefile.in +++ /dev/null @@ -1,603 +0,0 @@ -# Makefile.in generated by automake 1.11.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/pluto/plugins/xauth -DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \ - $(top_srcdir)/m4/config/ltoptions.m4 \ - $(top_srcdir)/m4/config/ltsugar.m4 \ - $(top_srcdir)/m4/config/ltversion.m4 \ - $(top_srcdir)/m4/config/lt~obsolete.m4 \ - $(top_srcdir)/m4/macros/with.m4 \ - $(top_srcdir)/m4/macros/enable-disable.m4 \ - $(top_srcdir)/m4/macros/add-plugin.m4 \ - $(top_srcdir)/configure.in -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__installdirs = "$(DESTDIR)$(plugindir)" -LTLIBRARIES = $(plugin_LTLIBRARIES) -libstrongswan_xauth_la_LIBADD = -am_libstrongswan_xauth_la_OBJECTS = xauth_plugin.lo \ - xauth_default_provider.lo xauth_default_verifier.lo -libstrongswan_xauth_la_OBJECTS = $(am_libstrongswan_xauth_la_OBJECTS) -libstrongswan_xauth_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libstrongswan_xauth_la_LDFLAGS) $(LDFLAGS) -o $@ -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libstrongswan_xauth_la_SOURCES) -DIST_SOURCES = $(libstrongswan_xauth_la_SOURCES) -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BTLIB = @BTLIB@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLIB = @DLLIB@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -GPERF = @GPERF@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -MYSQLCFLAG = @MYSQLCFLAG@ -MYSQLCONFIG = @MYSQLCONFIG@ -MYSQLLIB = @MYSQLLIB@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PTHREADLIB = @PTHREADLIB@ -RANLIB = @RANLIB@ -RTLIB = @RTLIB@ -RUBY = @RUBY@ -RUBYINCLUDE = @RUBYINCLUDE@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SOCKLIB = @SOCKLIB@ -STRIP = @STRIP@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -attest_plugins = @attest_plugins@ -axis2c_CFLAGS = @axis2c_CFLAGS@ -axis2c_LIBS = @axis2c_LIBS@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -c_plugins = @c_plugins@ -clearsilver_LIBS = @clearsilver_LIBS@ -datadir = @datadir@ -datarootdir = @datarootdir@ -dbusservicedir = @dbusservicedir@ -default_pkcs11 = @default_pkcs11@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -gtk_CFLAGS = @gtk_CFLAGS@ -gtk_LIBS = @gtk_LIBS@ -h_plugins = @h_plugins@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -imcvdir = @imcvdir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -ipsecdir = @ipsecdir@ -ipsecgroup = @ipsecgroup@ -ipseclibdir = @ipseclibdir@ -ipsecuser = @ipsecuser@ -libcharon_plugins = @libcharon_plugins@ -libdir = @libdir@ -libexecdir = @libexecdir@ -linux_headers = @linux_headers@ -localedir = @localedir@ -localstatedir = @localstatedir@ -lt_ECHO = @lt_ECHO@ -maemo_CFLAGS = @maemo_CFLAGS@ -maemo_LIBS = @maemo_LIBS@ -manager_plugins = @manager_plugins@ -mandir = @mandir@ -medsrv_plugins = @medsrv_plugins@ -mkdir_p = @mkdir_p@ -nm_CFLAGS = @nm_CFLAGS@ -nm_LIBS = @nm_LIBS@ -nm_ca_dir = @nm_ca_dir@ -oldincludedir = @oldincludedir@ -openac_plugins = @openac_plugins@ -p_plugins = @p_plugins@ -pcsclite_CFLAGS = @pcsclite_CFLAGS@ -pcsclite_LIBS = @pcsclite_LIBS@ -pdfdir = @pdfdir@ -piddir = @piddir@ -pki_plugins = @pki_plugins@ -plugindir = @plugindir@ -pluto_plugins = @pluto_plugins@ -pool_plugins = @pool_plugins@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -random_device = @random_device@ -resolv_conf = @resolv_conf@ -routing_table = @routing_table@ -routing_table_prio = @routing_table_prio@ -s_plugins = @s_plugins@ -sbindir = @sbindir@ -scepclient_plugins = @scepclient_plugins@ -scripts_plugins = @scripts_plugins@ -sharedstatedir = @sharedstatedir@ -soup_CFLAGS = @soup_CFLAGS@ -soup_LIBS = @soup_LIBS@ -srcdir = @srcdir@ -starter_plugins = @starter_plugins@ -strongswan_conf = @strongswan_conf@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -urandom_device = @urandom_device@ -xml_CFLAGS = @xml_CFLAGS@ -xml_LIBS = @xml_LIBS@ -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libfreeswan -I$(top_srcdir)/src/whack \ - -I$(top_srcdir)/src/pluto - -AM_CFLAGS = -rdynamic -plugin_LTLIBRARIES = libstrongswan-xauth.la -libstrongswan_xauth_la_SOURCES = \ - xauth_plugin.h xauth_plugin.c \ - xauth_default_provider.c xauth_default_provider.h \ - xauth_default_verifier.c xauth_default_verifier.h - -libstrongswan_xauth_la_LDFLAGS = -module -avoid-version -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/pluto/plugins/xauth/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/pluto/plugins/xauth/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) - @$(NORMAL_INSTALL) - test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ - } - -uninstall-pluginLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ - done - -clean-pluginLTLIBRARIES: - -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) - @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libstrongswan-xauth.la: $(libstrongswan_xauth_la_OBJECTS) $(libstrongswan_xauth_la_DEPENDENCIES) - $(libstrongswan_xauth_la_LINK) -rpath $(plugindir) $(libstrongswan_xauth_la_OBJECTS) $(libstrongswan_xauth_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_default_provider.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_default_verifier.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xauth_plugin.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(plugindir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - `test -z '$(STRIP)' || \ - echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pluginLTLIBRARIES - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pluginLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-pluginLTLIBRARIES ctags distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am install-man \ - install-pdf install-pdf-am install-pluginLTLIBRARIES \ - install-ps install-ps-am install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags uninstall uninstall-am uninstall-pluginLTLIBRARIES - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/pluto/plugins/xauth/xauth_default_provider.c b/src/pluto/plugins/xauth/xauth_default_provider.c deleted file mode 100644 index 77c5facc4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_default_provider.h" - -typedef struct private_xauth_default_provider_t private_xauth_default_provider_t; - -/** - * private data of xauth_default_provider - */ -struct private_xauth_default_provider_t { - - /** - * public functions - */ - xauth_provider_t public; -}; - -METHOD(xauth_provider_t, get_secret, bool, - private_xauth_default_provider_t *this, connection_t *c, chunk_t *secret) -{ - identification_t *user, *server; - - server = c->spd.that.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.this.id; - - return get_xauth_secret(user, server, secret); -} - -METHOD(xauth_provider_t, destroy, void, - private_xauth_default_provider_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -xauth_provider_t *xauth_default_provider_create() -{ - private_xauth_default_provider_t *this; - - INIT(this, - .public = { - .get_secret = _get_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_provider.h b/src/pluto/plugins/xauth/xauth_default_provider.h deleted file mode 100644 index ff1a91d16..000000000 --- a/src/pluto/plugins/xauth/xauth_default_provider.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_provider xauth_default_provider - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_PROVIDER_H_ -#define XAUTH_DEFAULT_PROVIDER_H_ - -#include - - -/** - * Create an xauth_default_provider instance. - */ -xauth_provider_t *xauth_default_provider_create(); - -#endif /** XAUTH_DEFAULT_PROVIDER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.c b/src/pluto/plugins/xauth/xauth_default_verifier.c deleted file mode 100644 index ca2e36aa0..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_default_verifier.h" - -typedef struct private_xauth_default_verifier_t private_xauth_default_verifier_t; - -/** - * private data of xauth_default_verifier - */ -struct private_xauth_default_verifier_t { - - /** - * public functions - */ - xauth_verifier_t public; -}; - -METHOD(xauth_verifier_t, verify_secret, bool, - private_xauth_default_verifier_t *this, connection_t *c, chunk_t secret) -{ - identification_t *user, *server; - chunk_t xauth_secret; - bool success = FALSE; - - server = c->spd.this.id; - user = (c->xauth_identity) ? c->xauth_identity : c->spd.that.id; - - if (get_xauth_secret(user, server, &xauth_secret)) - { - success = chunk_equals(secret, xauth_secret); - - if (!success && secret.len && secret.ptr[secret.len - 1] == 0) - { /* fix for null-terminated passwords (e.g. from Android 4) */ - secret.len--; - success = chunk_equals(secret, xauth_secret); - } - - chunk_clear(&xauth_secret); - } - return success; -} - -METHOD(xauth_verifier_t, destroy, void, - private_xauth_default_verifier_t *this) -{ - free(this); -} - - -/* - * Described in header. - */ -xauth_verifier_t *xauth_default_verifier_create() -{ - private_xauth_default_verifier_t *this; - - INIT(this, - .public = { - .verify_secret = _verify_secret, - .destroy = _destroy, - } - ); - - return &this->public; -} - diff --git a/src/pluto/plugins/xauth/xauth_default_verifier.h b/src/pluto/plugins/xauth/xauth_default_verifier.h deleted file mode 100644 index e5814d7b4..000000000 --- a/src/pluto/plugins/xauth/xauth_default_verifier.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_default_verifier xauth_default_verifier - * @{ @ingroup xauth - */ - -#ifndef XAUTH_DEFAULT_VERIFIER_H_ -#define XAUTH_DEFAULT_VERIFIER_H_ - -#include - - -/** - * Create an xauth_default_verifier instance. - */ -xauth_verifier_t *xauth_default_verifier_create(); - -#endif /** XAUTH_DEFAULT_VERIFIER_H_ @}*/ - diff --git a/src/pluto/plugins/xauth/xauth_plugin.c b/src/pluto/plugins/xauth/xauth_plugin.c deleted file mode 100644 index bfc4820ed..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include - -#include "xauth_plugin.h" -#include "xauth_default_provider.h" -#include "xauth_default_verifier.h" - -METHOD(plugin_t, get_name, char*, - xauth_plugin_t *this) -{ - return "xauth"; -} - -METHOD(plugin_t, destroy, void, - xauth_plugin_t *this) -{ - free(this); -} - -/* - * see header file - */ -plugin_t *xauth_plugin_create() -{ - xauth_plugin_t *this; - - INIT(this, - .plugin = { - .get_name = _get_name, - .reload = (void*)return_false, - .destroy = _destroy, - }, - ); - - pluto->xauth->add_provider(pluto->xauth, xauth_default_provider_create()); - pluto->xauth->add_verifier(pluto->xauth, xauth_default_verifier_create()); - - return &this->plugin; -} - diff --git a/src/pluto/plugins/xauth/xauth_plugin.h b/src/pluto/plugins/xauth/xauth_plugin.h deleted file mode 100644 index 4f14828d2..000000000 --- a/src/pluto/plugins/xauth/xauth_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth xauth - * @ingroup pplugins - * - * @defgroup xauth_plugin xauth_plugin - * @{ @ingroup xauth - */ - -#ifndef XAUTH_PLUGIN_H_ -#define XAUTH_PLUGIN_H_ - -#include - -typedef struct xauth_plugin_t xauth_plugin_t; - -/** - * XAUTH plugin - */ -struct xauth_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** XAUTH_PLUGIN_H_ @}*/ diff --git a/src/pluto/pluto.8 b/src/pluto/pluto.8 deleted file mode 100644 index ed6f78050..000000000 --- a/src/pluto/pluto.8 +++ /dev/null @@ -1,1594 +0,0 @@ -.TH IPSEC_PLUTO 8 "28 March 1999" -.SH NAME -pluto \- IPsec IKE keying daemon and control interface -.PP -whack \- control interface for IKE keying daemon -.SH SYNOPSIS -.na -.nh -.HP -.ft B -ipsec pluto -[\-\-help] -[\-\-version] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-nofork] -[\-\-stderrlog] -[\-\-uniqueids] -[\fB\-\-interface\fP \fIinterfacename\fP] -[\-\-ikeport\ \c -\fIportnumber\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-secretsfile\ \c -\fIsecrets\(hyfile\fP] -[\-\-adns \fIpathname\fP] -[\-\-lwdnsq \fIpathname\fP] -[\-\-perpeerlog] -[\-\-perpeerlogbase\ \c -\fIdirname\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -.HP -.ft B -ipsec whack -[\-\-help] -[\-\-version] -.HP -.ft B -ipsec whack -\-\-name\ \c -\fIconnection-name\fP -.br -[\-\-id\ \c -\fIid\fP] \c -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -\-\-to -.br -[\-\-id\ \c -\fIid\fP] -[\-\-host\ \c -\fIip\(hyaddress\fP] -[\-\-ikeport\ \c -\fIport\(hynumber\fP] -[\-\-nexthop\ \c -\fIip\(hyaddress\fP] -[\-\-client\ \c -\fIsubnet\fP] -[\-\-dnskeyondemand] -[\-\-updown\ \c -\fIupdown\fP] -.br -[\-\-psk] -[\-\-rsasig] -[\-\-encrypt] -[\-\-authenticate] -[\-\-compress] -[\-\-tunnel] -[\-\-pfs] -[\-\-disablearrivalcheck] -[\-\-ipv4] -[\-\-ipv6] -[\-\-tunnelipv4] -[\-\-tunnelipv6] -[\-\-ikelifetime\ \c -\fIseconds\fP] -[\-\-ipseclifetime\ \c -\fIseconds\fP] -[\-\-rekeymargin\ \c -\fIseconds\fP] -[\-\-rekeyfuzz\ \c -\fIpercentage\fP] -[\-\-keyingtries\ \c -\fIcount\fP] -[\-\-dontrekey] -[\-\-delete] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-keyid\ \c -\fIid\fP -[\-\-addkey] -[\-\-pubkeyrsa\ \c -\fIkey\fP] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-myid\ \c -\fIid\fP -.HP -.ft B -ipsec whack -\-\-listen|\-\-unlisten -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-route|\-\-unroute -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-initiate|\-\-terminate -\-\-name\ \c -\fIconnection-name\fP -[\-\-asynchronous] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-tunnelipv4] -[\-\-tunnelipv6] -\-\-oppohere \fIip\(hyaddress\fP -\-\-oppothere \fIip\(hyaddress\fP -.HP -.ft B -ipsec whack -\-\-delete -\-\-name\ \c -\fIconnection-name\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-deletestate\ \c -\fIstate-number\fP -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -[\-\-name\ \c -\fIconnection-name\fP] -[\-\-debug\(hynone] -[\-\-debug\(hyall] -[\-\-debug\(hyraw] -[\-\-debug\(hycrypt] -[\-\-debug\(hyparsing] -[\-\-debug\(hyemitting] -[\-\-debug\(hycontrol] -[\-\-debug\(hylifecycle] -[\-\-debug\(hykernel] -[\-\-debug\(hydns] -[\-\-debug\(hyoppo] -[\-\-debug\(hyprivate] -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-status -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.HP -.ft B -ipsec whack -\-\-shutdown -[\-\-ctlbase\ \c -\fIpath\fP] -[\-\-optionsfrom\ \c -\fIfilename\fP] -[\-\-label\ \c -\fIstring\fP] -.ft R -.hy -.ad -.SH DESCRIPTION -.BR pluto -is an IKE (``IPsec Key Exchange'') daemon. -.BR whack -is an auxiliary program to allow requests to be made to a running -.BR pluto . -.LP -.BR pluto -is used to automatically build shared ``security associations'' on a -system that has IPsec, the secure IP protocol. -In other words, -.BR pluto -can eliminate much of the work of manual keying. -The actual -secure transmission of packets is the responsibility of the Linux kernel. -\fIipsec_auto\fP(8) provides a more convenient interface to -\fBpluto\fP and \fBwhack\fP. -.SS IKE's Job -.LP -A \fISecurity Association\fP (\fISA\fP) is an agreement between two network nodes on -how to process certain traffic between them. This processing involves -encapsulation, authentication, encryption, or compression. -.LP -IKE can be deployed on a network node to negotiate Security -Associations for that node. These IKE implementations can only -negotiate with other IKE implementations, so IKE must be on each node -that is to be an endpoint of an IKE-negotiated Security Association. -No other nodes need to be running IKE. -.LP -An IKE instance (i.e. an IKE implementation on a particular network -node) communicates with another IKE instance using UDP IP packets, so -there must be a route between the nodes in each direction. -.LP -The negotiation of Security Associations requires a number of choices -that involve tradeoffs between security, convenience, trust, and -efficiency. These are policy issues and are normally specified to the -IKE instance by the system administrator. -.LP -IKE deals with two kinds of Security Associations. The first part of -a negotiation between IKE instances is to build an ISAKMP SA. An -ISAKMP SA is used to protect communication between the two IKEs. -IPsec SAs can then be built by the IKEs \- these are used to carry -protected IP traffic between the systems. -.LP -The negotiation of the ISAKMP SA is known as Phase 1. In theory, -Phase 1 can be accomplished by a couple of different exchange types, -but we only implement one called Main Mode (we don't implement -Aggressive Mode). -.LP -Any negotiation under the protection of an ISAKMP SA, including the -negotiation of IPsec SAs, is part of Phase 2. The exchange type -that we use to negotiate an IPsec SA is called Quick Mode. -.LP -IKE instances must be able to authenticate each other as part of their -negotiation of an ISAKMP SA. This can be done by several mechanisms -described in the draft standards. -.LP -IKE negotiation can be initiated by any instance with any other. If -both can find an agreeable set of characteristics for a Security -Association, and both recognize each others authenticity, they can set -up a Security Association. The standards do not specify what causes -an IKE instance to initiate a negotiation. -.LP -In summary, an IKE instance is prepared to automate the management of -Security Associations in an IPsec environment, but a number of issues -are considered policy and are left in the system administrator's hands. -.SS Pluto -.LP -\fBpluto\fP is an implementation of IKE. It runs as a daemon on a network -node. Currently, this network node must be a Linux 2.6 system running the -native \fBNETKEY\fP IPsec stack. -.LP -\fBpluto\fP only implements a subset of IKE. This is enough for it to -interoperate with other instances of \fBpluto\fP, and many other IKE -implementations. We are working on implementing more of IKE. -.LP -The policy for acceptable characteristics for Security Associations is -mostly hardwired into the code of \fBpluto\fP (spdb.c). Eventually -this will be moved into a security policy database with reasonable -expressive power and more convenience. -.LP -\fBpluto\fP uses shared secrets or RSA signatures to authenticate -peers with whom it is negotiating. -.LP -\fBpluto\fP initiates negotiation of a Security Association when it is -manually prodded: the program \fBwhack\fP is run to trigger this. -It will also initiate a negotiation when the Linux kernel traps an outbound -packet for Opportunistic Encryption. -.LP -\fBpluto\fP implements ISAKMP SAs itself. After it has negotiated the -characteristics of an IPsec SA, it directs the Linux kernel to implement it. -It also invokes a script to adjust any firewall and issue \fIroute\fP(8) -commands. -.LP -When \fBpluto\fP shuts down, it closes all Security Associations. -.SS Before Running Pluto -.LP -\fBpluto\fP runs as a daemon with userid root. Before running it, a few -things must be set up. -.LP -\fBpluto\fP requires a Linux 2.6 kernel with the modules for the native IPsec -stack enabled. -.LP -\fBpluto\fP supports multiple public networks (that is, networks -that are considered insecure and thus need to have their traffic -encrypted or authenticated). It discovers the -public interfaces to use by looking at all interfaces that are -configured (the \fB\-\-interface\fP option can be used to limit -the interfaces considered). -It does this only when \fBwhack\fP tells it to \-\-listen, -so the interfaces must be configured by then. -\fIifconfig\fP(8) with the \fB\-a\fP flag will show -the name and status of each network interface. -.LP -\fBpluto\fP requires a database of preshared secrets and RSA private keys. -This is described in the -.IR ipsec.secrets (5). -\fBpluto\fP is told of RSA public keys via \fBwhack\fP commands. -If the connection is Opportunistic, and no RSA public key is known, -\fBpluto\fP will attempt to fetch RSA keys using the Domain Name System. -.SS ipsec.secrets file -.LP -A \fBpluto\fP daemon and another IKE daemon (for example, another instance -of \fBpluto\fP) must convince each other that they are who they are supposed -to be before any negotiation can succeed. This authentication is -accomplished by using either secrets that have been shared beforehand -(manually) or by using RSA signatures. There are other techniques, -but they have not been implemented in \fBpluto\fP. -.LP -The file \fI/etc/ipsec.secrets\fP is used to keep preshared secret keys -and RSA private keys for -authentication with other IKE daemons. For debugging, there is an -argument to the \fBpluto\fP command to use a different file. -This file is described in -.IR ipsec.secrets (5). -.SS Running Pluto -.LP -To fire up the daemon, just type \fBpluto\fP (be sure to be running as -the superuser). -The default IKE port number is 500, the UDP port assigned by IANA for IKE Daemons. -\fBpluto\fP must be run by the superuser to be able to use the UDP 500 port. -.LP -\fBpluto\fP attempts to create a lockfile with the name -\fI/var/run/pluto.pid\fP. If the lockfile cannot be created, -\fBpluto\fP exits \- this prevents multiple \fBpluto\fPs from -competing Any ``leftover'' lockfile must be removed before -\fBpluto\fP will run. \fBpluto\fP writes its pid into this file so -that scripts can find it. This lock will not function properly if it -is on an NFS volume (but sharing locks on multiple machines doesn't -make sense anyway). -.LP -\fBpluto\fP then forks and the parent exits. This is the conventional -``daemon fork''. It can make debugging awkward, so there is an option -to suppress this fork. -.LP -All logging, including diagnostics, is sent to -.IR syslog (3) -with facility=authpriv; -it decides where to put these messages (possibly in /var/log/secure). -Since this too can make debugging awkward, there is an option to -steer logging to stderr. -.LP -If the \fB\-\-perpeerlog\fP option is given, then pluto will open -a log file per connection. By default, this is in /var/log/pluto/peer, -in a subdirectory formed by turning all dot (.) [IPv4} or colon (:) -[IPv6] into slashes (/). -.LP -The base directory can be changed with the \fB\-\-perpeerlogbase\fP. -.LP -Once \fBpluto\fP is started, it waits for requests from \fBwhack\fP. -.SS Pluto's Internal State -.LP -To understand how to use \fBpluto\fP, it is helpful to understand a little -about its internal state. Furthermore, the terminology is needed to decipher -some of the diagnostic messages. -.LP -The \fI(potential) connection\fP database describes attributes of a -connection. These include the IP addresses of the hosts and client -subnets and the security characteristics desired. \fBpluto\fP -requires this information (simply called a connection) before it can -respond to a request to build an SA. Each connection is given a name -when it is created, and all references are made using this name. -.LP -During the IKE exchange to build an SA, the information about the -negotiation is represented in a \fIstate object\fP. Each state object -reflects how far the negotiation has reached. Once the negotiation is -complete and the SA established, the state object remains to represent -the SA. When the SA is terminated, the state object is discarded. -Each State object is given a serial number and this is used to refer -to the state objects in logged messages. -.LP -Each state object corresponds to a connection and can be thought of -as an instantiation of that connection. -At any particular time, there may be any number of state objects -corresponding to a particular connection. -Often there is one representing an ISAKMP SA and another representing -an IPsec SA. -.LP -Each connection may be routed, and must be while it has an IPsec SA. -The connection specifies the characteristics of the route: the -interface on this machine, the ``gateway'' (the nexthop), -and the peer's client subnet. Two -connections may not be simultaneously routed if they are for the same -peer's client subnet but use different interfaces or gateways -(\fBpluto\fP's logic does not reflect any advanced routing capabilities). -.LP -Each eroute is associated with the state object for an IPsec SA -because it has the particular characteristics of the SA. -Two eroutes conflict if they specify the identical local -and remote clients (unlike for routes, the local clients are -taken into account). -.LP -When \fBpluto\fP needs to install a route for a connection, -it must make sure that no conflicting route is in use. If another -connection has a conflicting route, that route will be taken down, as long -as there is no IPsec SA instantiating that connection. -If there is such an IPsec SA, the attempt to install a route will fail. -.LP -There is an exception. If \fBpluto\fP, as Responder, needs to install -a route to a fixed client subnet for a connection, and there is -already a conflicting route, then the SAs using the route are deleted -to make room for the new SAs. The rationale is that the new -connection is probably more current. The need for this usually is a -product of Road Warrior connections (these are explained later; they -cannot be used to initiate). -.LP -When \fBpluto\fP needs to install an eroute for an IPsec SA (for a -state object), first the state object's connection must be routed (if -this cannot be done, the eroute and SA will not be installed). -If a conflicting eroute is already in place for another connection, -the eroute and SA will not be installed (but note that the routing -exception mentioned above may have already deleted potentially conflicting SAs). -If another IPsec -SA for the same connection already has an eroute, all its outgoing traffic -is taken over by the new eroute. The incoming traffic will still be -processed. This characteristic is exploited during rekeying. -.LP -Some of these routing characteristics are specific to \fBKLIPS\fP, the FreeS/WAN -implementation of IPsec and are not relevant when running pluto on the native -Linux 2.6 IPsec stack. -.SS Using Whack -.LP -\fBwhack\fP is used to command a running \fBpluto\fP. -\fBwhack\fP uses a UNIX domain socket to speak to \fBpluto\fP -(by default, \fI/var/pluto.ctl\fP). -.LP -\fBwhack\fP has an intricate argument syntax. -This syntax allows many different functions to be specified. -The help form shows the usage or version information. -The connection form gives \fBpluto\fP a description of a potential connection. -The public key form informs \fBpluto\fP of the RSA public key for a potential peer. -The delete form deletes a connection description and all SAs corresponding -to it. -The listen form tells \fBpluto\fP to start or stop listening on the public interfaces -for IKE requests from peers. -The route form tells \fBpluto\fP to set up routing for a connection; -the unroute form undoes this. -The initiate form tells \fBpluto\fP to negotiate an SA corresponding to a connection. -The terminate form tells \fBpluto\fP to remove all SAs corresponding to a connection, -including those being negotiated. -The status form displays the \fBpluto\fP's internal state. -The debug form tells \fBpluto\fP to change the selection of debugging output -``on the fly''. The shutdown form tells -\fBpluto\fP to shut down, deleting all SAs. -.LP -Most options are specific to one of the forms, and will be described -with that form. There are three options that apply to all forms. -.TP -\fB\-\-ctlbase\fP\ \fIpath\fP -\fIpath\fP.ctl is used as the UNIX domain socket for talking -to \fBpluto\fP. -This option facilitates debugging. -.TP -\fB\-\-optionsfrom\fP\ \fIfilename\fP -adds the contents of the file to the argument list. -.TP -\fB\-\-label\fP\ \fIstring\fP -adds the string to all error messages generated by \fBwhack\fP. -.LP -The help form of \fBwhack\fP is self-explanatory. -.TP -\fB\-\-help\fP -display the usage message. -.TP -\fB\-\-version\fP -display the version of \fBwhack\fP. -.LP -The connection form describes a potential connection to \fBpluto\fP. -\fBpluto\fP needs to know what connections can and should be negotiated. -When \fBpluto\fP is the initiator, it needs to know what to propose. -When \fBpluto\fP is the responder, it needs to know enough to decide whether -is is willing to set up the proposed connection. -.LP -The description of a potential connection can specify a large number -of details. Each connection has a unique name. This name will appear -in a updown shell command, so it should not contain punctuation -that would make the command ill-formed. -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The topology of -a connection is symmetric, so to save space here is half a picture: - -\ \ \ client_subnet<\-\->host:ikeport<\-\->nexthop<\-\-\- - -A similar trick is used in the flags. The same flag names are used for -both ends. Those before the \fB\-\-to\fP flag describe the left side -and those afterwards describe the right side. When \fBpluto\fP attempts -to use the connection, it decides whether it is the left side or the right -side of the connection, based on the IP numbers of its interfaces. -.TP -\fB\-\-id\fP\ \fIid\fP -the identity of the end. Currently, this can be an IP address (specified -as dotted quad or as a Fully Qualified Domain Name, which will be resolved -immediately) or as a Fully Qualified Domain Name itself (prefixed by ``@'' -to signify that it should not be resolved), or as user@FQDN, or as the -magic value \fB%myid\fP. -\fBPluto\fP only authenticates the identity, and does not use it for -addressing, so, for example, an IP address need not be the one to which -packets are to be sent. If the option is absent, the -identity defaults to the IP address specified by \fB\-\-host\fP. -\fB%myid\fP allows the identity to be separately specified (by the \fBpluto\fP or \fBwhack\fP option \fB\-\-myid\fP -or by the \fBipsec.conf\fP(5) \fBconfig setup\fP parameter \fPmyid\fP). -Otherwise, \fBpluto\fP tries to guess what \fB%myid\fP should stand for: -the IP address of \fB%defaultroute\fP, if it is supported by a suitable TXT record in the reverse domain for that IP address, -or the system's hostname, if it is supported by a suitable TXT record in its forward domain. -.\" The identity is transmitted in the IKE protocol, and is what is authenticated. -.TP -\fB\-\-host\fP\ \fIip\(hyaddress\fP -.TP -\fB\-\-host\fP\ \fB%any\fP -.TP -\fB\-\-host\fP\ \fB%opportunistic\fP -the IP address of the end (generally the public interface). -If \fBpluto\fP is to act as a responder -for IKE negotiations initiated from unknown IP addresses (the -``Road Warrior'' case), the -IP address should be specified as \fB%any\fP (currently, -the obsolete notation \fB0.0.0.0\fP is also accepted for this). -If \fBpluto\fP is to opportunistically initiate the connection, -use \fB%opportunistic\fP -.TP -\fB\-\-ikeport\fP\ \fIport\(hynumber\fP -the UDP port that IKE listens to on that host. The default is 500. -(\fBpluto\fP on this machine uses the port specified by its own command -line argument, so this only affects where \fBpluto\fP sends messages.) -.TP -\fB\-\-nexthop\fP\ \fIip\(hyaddress\fP -where to route packets for the peer's client (presumably for the peer too, -but it will not be used for this). -When \fBpluto\fP installs an IPsec SA, it issues a route command. -It uses the nexthop as the gateway. -The default is the peer's IP address (this can be explicitly written as -\fB%direct\fP; the obsolete notation \fB0.0.0.0\fP is accepted). -This option is necessary if \fBpluto\fP's host's interface used for sending -packets to the peer is neither point-to-point nor directly connected to the -peer. -.TP -\fB\-\-client\fP\ \fIsubnet\fP -the subnet for which the IPsec traffic will be destined. If not specified, -the host will be the client. -The subnet can be specified in any of the forms supported by \fIipsec_atosubnet\fP(3). -The general form is \fIaddress\fP/\fImask\fP. The \fIaddress\fP can be either -a domain name or four decimal numbers (specifying octets) separated by dots. -The most convenient form of the \fImask\fP is a decimal integer, specifying -the number of leading one bits in the mask. So, for example, 10.0.0.0/8 -would specify the class A network ``Net 10''. -.TP -\fB\-\-dnskeyondemand]\fP -specifies that when an RSA public key is needed to authenticate this -host, and it isn't already known, fetch it from DNS. -.TP -\fB\-\-updown\fP\ \fIupdown\fP -specifies an external shell command to be run whenever \fBpluto\fP -brings up or down a connection. -The script is used to build a shell command, so it may contain positional -parameters, but ought not to have punctuation that would cause the -resulting command to be ill-formed. -The default is \fIipsec _updown\fP. -.TP -\fB\-\-to\fP -separates the specification of the left and right ends of the connection. -.LP -The potential connection description also specifies characteristics of -rekeying and security. -.TP -\fB\-\-psk\fP -Propose and allow preshared secret authentication for IKE peers. This authentication -requires that each side use the same secret. May be combined with \fB\-\-rsasig\fP; -at least one must be specified. -.TP -\fB\-\-rsasig\fP -Propose and allow RSA signatures for authentication of IKE peers. This authentication -requires that each side have have a private key of its own and know the -public key of its peer. May be combined with \fB\-\-psk\fP; -at least one must be specified. -.TP -\fB\-\-encrypt\fP -All proposed or accepted IPsec SAs will include non-null ESP. -The actual choices of transforms are wired into \fBpluto\fP. -.TP -\fB\-\-authenticate\fP -All proposed IPsec SAs will include AH. -All accepted IPsec SAs will include AH or ESP with authentication. -The actual choices of transforms are wired into \fBpluto\fP. -Note that this has nothing to do with IKE authentication. -.TP -\fB\-\-compress\fP -All proposed IPsec SAs will include IPCOMP (compression). -This will be ignored if the kernel is not configured with IPCOMP support. -.TP -\fB\-\-tunnel\fP -the IPsec SA should use tunneling. Implicit if the SA is for clients. -Must only be used with \fB\-\-authenticate\fP or \fB\-\-encrypt\fP. -.TP -\fB\-\-ipv4\fP -The host addresses will be interpreted as IPv4 addresses. This is the -default. Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-ipv6\fP -The host addresses (including nexthop) will be interpreted as IPv6 addresses. -Note that for a connection, all host addresses must be of -the same Address Family (IPv4 and IPv6 use different Address Families). -.TP -\fB\-\-tunnelipv4\fP -The client addresses will be interpreted as IPv4 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-tunnelipv6\fP -The client addresses will be interpreted as IPv6 addresses. The default is -to match what the host will be. This does not imply \fB\-\-tunnel\fP so the -flag can be safely used when no tunnel is actually specified. -Note that for a connection, all tunnel addresses must be of the same -Address Family. -.TP -\fB\-\-pfs\fP -There should be Perfect Forward Secrecy \- new keying material will -be generated for each IPsec SA rather than being derived from the ISAKMP -SA keying material. -Since the group to be used cannot be negotiated (a dubious feature of the -standard), \fBpluto\fP will propose the same group that was used during Phase 1. -We don't implement a stronger form of PFS which would require that the -ISAKMP SA be deleted after the IPSEC SA is negotiated. -.TP -\fB\-\-disablearrivalcheck\fP -If the connection is a tunnel, allow packets arriving through the tunnel -to have any source and destination addresses. -.LP -If none of the \fB\-\-encrypt\fP, \fB\-\-authenticate\fP, \fB\-\-compress\fP, -or \fB\-\-pfs\fP flags is given, the initiating the connection will -only build an ISAKMP SA. For such a connection, client subnets have -no meaning and must not be specified. -.LP -More work is needed to allow for flexible policies. Currently -policy is hardwired in the source file spdb.c. The ISAKMP SAs may use -Oakley groups MODP1024 and MODP1536; 3DES encryption; SHA1-96 -and MD5-96 authentication. The IPsec SAs may use 3DES and -MD5-96 or SHA1-96 for ESP, or just MD5-96 or SHA1-96 for AH. -IPCOMP Compression is always Deflate. -.TP -\fB\-\-ikelifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an ISAKMP SA be allowed to live. -The default is 10800 (three hours) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-ipseclifetime\fP\ \fIseconds\fP -how long \fBpluto\fP will propose that an IPsec SA be allowed to live. -The default is 3600 (one hour) and the maximum is 86400 (one day). -This option will not affect what is accepted. -\fBpluto\fP will reject proposals that exceed the maximum. -.TP -\fB\-\-rekeymargin\fP\ \fIseconds\fP -how long before an SA's expiration should \fBpluto\fP try to negotiate -a replacement SA. This will only happen if \fBpluto\fP was the initiator. -The default is 540 (nine minutes). -.TP -\fB\-\-rekeyfuzz\fP\ \fIpercentage\fP -maximum size of random component to add to rekeymargin, expressed as -a percentage of rekeymargin. \fBpluto\fP will select a delay uniformly -distributed within this range. By default, the percentage will be 100. -If greater determinism is desired, specify 0. It may be appropriate -for the percentage to be much larger than 100. -.TP -\fB\-\-keyingtries\fP\ \fIcount\fP -how many times \fBpluto\fP should try to negotiate an SA, -either for the first time or for rekeying. -A value of 0 is interpreted as a very large number: never give up. -The default is three. -.TP -\fB\-\-dontrekey\fP -A misnomer. -Only rekey a connection if we were the Initiator and there was recent -traffic on the existing connection. -This applies to Phase 1 and Phase 2. -This is currently the only automatic way for a connection to terminate. -It may be useful with Road Warrior or Opportunistic connections. -.br -Since SA lifetime negotiation is take-it-or-leave it, a Responder -normally uses the shorter of the negotiated or the configured lifetime. -This only works because if the lifetime is shorter than negotiated, -the Responder will rekey in time so that everything works. -This interacts badly with \fB\-\-dontrekey\fP. In this case, -the Responder will end up rekeying to rectify a shortfall in an IPsec SA -lifetime; for an ISAKMP SA, the Responder will accept the negotiated -lifetime. -.TP -\fB\-\-delete\fP -when used in the connection form, it causes any previous connection -with this name to be deleted before this one is added. Unlike a -normal delete, no diagnostic is produced if there was no previous -connection to delete. Any routing in place for the connection is undone. -.LP -The delete form deletes a named connection description and any -SAs established or negotiations initiated using this connection. -Any routing in place for the connection is undone. -.TP -\fB\-\-delete\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The deletestate form deletes the state object with the specified serial number. -This is useful for selectively deleting instances of connections. -.TP -\fB\-\-deletestate\fP\ \fIstate-number\fP -.LP -The route form of the \fBwhack\fP command tells \fBpluto\fP to set up -routing for a connection. -Although like a traditional route, it uses an ipsec device as a -virtual interface. -Once routing is set up, no packets will be -sent ``in the clear'' to the peer's client specified in the connection. -A TRAP shunt eroute will be installed; if outbound traffic is caught, -Pluto will initiate the connection. -An explicit \fBwhack\fP route is not always needed: if it hasn't been -done when an IPsec SA is being installed, one will be automatically attempted. -.LP -When a routing is attempted for a connection, there must not already -be a routing for a different connection with the same subnet but different -interface or destination, or if -there is, it must not be being used by an IPsec SA. Otherwise the -attempt will fail. -.TP -\fB\-\-route\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The unroute form of the \fBwhack\fP command tells \fBpluto\fP to undo -a routing. \fBpluto\fP will refuse if an IPsec SA is using the connection. -If another connection is sharing the same routing, it will be left in place. -Without a routing, packets will be sent without encryption or authentication. -.TP -\fB\-\-unroute\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The initiate form tells \fBpluto\fP to initiate a negotiation with another -\fBpluto\fP (or other IKE daemon) according to the named connection. -Initiation requires a route that \fB\-\-route\fP would provide; -if none is in place at the time an IPsec SA is being installed, -\fBpluto\fP attempts to set one up. -.TP -\fB\-\-initiate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.TP -\fB\-\-asynchronous -.LP -The initiate form of the \fBwhack\fP command will relay back from -\fBpluto\fP status information via the UNIX domain socket (unless -\-\-asynchronous is specified). The status information is meant to -look a bit like that from \fBFTP\fP. Currently \fBwhack\fP simply -copies this to stderr. When the request is finished (eg. the SAs are -established or \fBpluto\fP gives up), \fBpluto\fP closes the channel, -causing \fBwhack\fP to terminate. -.LP -The opportunistic initiate form is mainly used for debugging. -.TP -\fB\-\-tunnelipv4\fP -.TP -\fB\-\-tunnelipv6\fP -.TP -\fB\-\-oppohere\fP\ \fIip-address\fP -.TP -\fB\-\-oppothere\fP\ \fIip-address\fP -.LP -This will cause \fBpluto\fP to attempt to opportunistically initiate a -connection from here to the there, even if a previous attempt -had been made. -The whack log will show the progress of this attempt. -.LP -The terminate form tells \fBpluto\fP to delete any SAs that use the specified -connection and to stop any negotiations in process. -It does not prevent new negotiations from starting (the delete form -has this effect). -.TP -\fB\-\-terminate\fP -.TP -\fB\-\-name\fP\ \fIconnection-name\fP -.LP -The public key for informs \fBpluto\fP of the RSA public key for a potential peer. -Private keys must be kept secret, so they are kept in -.IR ipsec.secrets (5). -.TP -\fB\-\-keyid\ \fP\fIid\fP -specififies the identity of the peer for which a public key should be used. -Its form is identical to the identity in the connection. -If no public key is specified, \fBpluto\fP attempts to find KEY records -from DNS for the id (if a FQDN) or through reverse lookup (if an IP address). -Note that there several interesting ways in which this is not secure. -.TP -\fB\-\-addkey\fP -specifies that the new key is added to the collection; otherwise the -new key replaces any old ones. -.TP -\fB\-\-pubkeyrsa\ \fP\fIkey\fP -specifies the value of the RSA public key. It is a sequence of bytes -as described in RFC 2537 ``RSA/MD5 KEYs and SIGs in the Domain Name System (DNS)''. -It is denoted in a way suitable for \fIipsec_ttodata\fP(3). -For example, a base 64 numeral starts with 0s. -.LP -The listen form tells \fBpluto\fP to start listening for IKE requests -on its public interfaces. To avoid race conditions, it is normal to -load the appropriate connections into \fBpluto\fP before allowing it -to listen. If \fBpluto\fP isn't listening, it is pointless to -initiate negotiations, so it will refuse requests to do so. Whenever -the listen form is used, \fBpluto\fP looks for public interfaces and -will notice when new ones have been added and when old ones have been -removed. This is also the trigger for \fBpluto\fP to read the -\fIipsec.secrets\fP file. So listen may useful more than once. -.TP -\fB\-\-listen\fP -start listening for IKE traffic on public interfaces. -.TP -\fB\-\-unlisten\fP -stop listening for IKE traffic on public interfaces. -.LP -The status form will display information about the internal state of -\fBpluto\fP: information about each potential connection, about -each state object, and about each shunt that \fBpluto\fP is managing -without an associated connection. -.TP -\fB\-\-status\fP -.LP -The shutdown form is the proper way to shut down \fBpluto\fP. -It will tear down the SAs on this machine that \fBpluto\fP has negotiated. -It does not inform its peers, so the SAs on their machines remain. -.TP -\fB\-\-shutdown\fP -.SS Examples -.LP -It would be normal to start \fBpluto\fP in one of the system initialization -scripts. It needs to be run by the superuser. Generally, no arguments are needed. -To run in manually, the superuser can simply type - -\ \ \ ipsec pluto - -The command will immediately return, but a \fBpluto\fP process will be left -running, waiting for requests from \fBwhack\fP or a peer. -.LP -Using \fBwhack\fP, several potential connections would be described: -.HP -.na -\ \ \ ipsec whack \-\-name\ silly -\-\-host\ 127.0.0.1 \-\-to \-\-host\ 127.0.0.2 -\-\-ikelifetime\ 900 \-\-ipseclifetime\ 800 \-\-keyingtries\ 3 -.ad -.LP -Since this silly connection description specifies neither encryption, -authentication, nor tunneling, it could only be used to establish -an ISAKMP SA. -.HP -.na -\ \ \ ipsec whack \-\-name\ secret \-\-host\ 10.0.0.1 \-\-client\ 10.0.1.0/24 -\-\-to \-\-host\ 10.0.0.2 \-\-client\ 10.0.2.0/24 -\-\-encrypt -.ad -.LP -This is something that must be done on both sides. If the other -side is \fBpluto\fP, the same \fBwhack\fP command could be used on it -(the command syntax is designed to not distinguish which end is ours). -.LP -Now that the connections are specified, \fBpluto\fP is ready to handle -requests and replies via the public interfaces. We must tell it to discover -those interfaces and start accepting messages from peers: - -\ \ \ ipsec whack \-\-listen -.LP -If we don't immediately wish to bring up a secure connection between -the two clients, we might wish to prevent insecure traffic. -The routing form asks \fBpluto\fP to cause the packets sent from -our client to the peer's client to be routed through the ipsec0 -device; if there is no SA, they will be discarded: - -\ \ \ ipsec whack \-\-route secret -.LP -Finally, we are ready to get \fBpluto\fP to initiate negotiation -for an IPsec SA (and implicitly, an ISAKMP SA): - -\ \ \ ipsec whack \-\-initiate\ \-\-name\ secret - -A small log of interesting events will appear on standard output -(other logging is sent to syslog). -.LP -\fBwhack\fP can also be used to terminate \fBpluto\fP cleanly, tearing down -all SAs that it has negotiated. - -\ \ \ ipsec whack \-\-shutdown - -Notification of any IPSEC SA deletion, but not ISAKMP SA deletion -is sent to the peer. Unfortunately, such Notification is not reliable. -Furthermore, \fBpluto\fP itself ignores Notifications. -.SS The updown command -.LP -Whenever \fBpluto\fP brings a connection up or down, it invokes -the updown command. This command is specified using the \fB\-\-updown\fP -option. This allows for customized control over routing and firewall manipulation. -.LP -The updown is invoked for five different operations. Each of -these operations can be for our client subnet or for our host itself. -.TP -\fBprepare-host\fP or \fBprepare-client\fP -is run before bringing up a new connection if no other connection -with the same clients is up. Generally, this is useful for deleting a -route that might have been set up before \fBpluto\fP was run or -perhaps by some agent not known to \fBpluto\fP. -.TP -\fBroute-host\fP or \fBroute-client\fP -is run when bringing up a connection for a new peer client subnet -(even if \fBprepare-host\fP or \fBprepare-client\fP was run). The -command should install a suitable route. Routing decisions are based -only on the destination (peer's client) subnet address, unlike eroutes -which discriminate based on source too. -.TP -\fBunroute-host\fP or \fBunroute-client\fP -is run when bringing down the last connection for a particular peer -client subnet. It should undo what the \fBroute-host\fP or \fBroute-client\fP -did. -.TP -\fBup-host\fP or \fBup-client\fP -is run when bringing up a tunnel eroute with a pair of client subnets -that does not already have a tunnel eroute. -This command should install firewall rules as appropriate. -It is generally a good idea to allow IKE messages (UDP port 500) -travel between the hosts. -.TP -\fBdown-host\fP or \fBdown-client\fP -is run when bringing down the eroute for a pair of client subnets. -This command should delete firewall rules as appropriate. Note that -there may remain some inbound IPsec SAs with these client subnets. -.LP -The script is passed a large number of environment variables to specify -what needs to be done. -.TP -\fBPLUTO_VERSION\fP -indicates what version of this interface is being used. This document -describes version 1.1. This is upwardly compatible with version 1.0. -.TP -\fBPLUTO_VERB\fP -specifies the name of the operation to be performed -(\fBprepare-host\fP,r \fBprepare-client\fP, -\fBup-host\fP, \fBup-client\fP, -\fBdown-host\fP, or \fBdown-client\fP). If the address family for -security gateway to security gateway communications is IPv6, then -a suffix of \-v6 is added to the verb. -.TP -\fBPLUTO_CONNECTION\fP -is the name of the connection for which we are routing. -.TP -\fBPLUTO_NEXT_HOP\fP -is the next hop to which packets bound for the peer must be sent. -.TP -\fBPLUTO_INTERFACE\fP -is the name of the ipsec interface to be used. -.TP -\fBPLUTO_ME\fP -is the IP address of our host. -.TP -\fBPLUTO_MY_CLIENT\fP -is the IP address / count of our client subnet. -If the client is just the host, this will be the host's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_MY_CLIENT_NET\fP -is the IP address of our client net. -If the client is just the host, this will be the host's own IP address. -.TP -\fBPLUTO_MY_CLIENT_MASK\fP -is the mask for our client net. -If the client is just the host, this will be 255.255.255.255. -.TP -\fBPLUTO_PEER\fP -is the IP address of our peer. -.TP -\fBPLUTO_PEER_CLIENT\fP -is the IP address / count of the peer's client subnet. -If the client is just the peer, this will be the peer's own IP address / max -(where max is 32 for IPv4 and 128 for IPv6). -.TP -\fBPLUTO_PEER_CLIENT_NET\fP -is the IP address of the peer's client net. -If the client is just the peer, this will be the peer's own IP address. -.TP -\fBPLUTO_PEER_CLIENT_MASK\fP -is the mask for the peer's client net. -If the client is just the peer, this will be 255.255.255.255. -.LP -All output sent by the script to stderr or stdout is logged. The -script should return an exit status of 0 if and only if it succeeds. -.LP -\fBPluto\fP waits for the script to finish and will not do any other -processing while it is waiting. -The script may assume that \fBpluto\fP will not change anything -while the script runs. -The script should avoid doing anything that takes much time and it -should not issue any command that requires processing by \fBpluto\fP. -Either of these activities could be performed by a background -subprocess of the script. -.SS Rekeying -.LP -When an SA that was initiated by \fBpluto\fP has only a bit of -lifetime left, -\fBpluto\fP will initiate the creation of a new SA. This applies to -ISAKMP and IPsec SAs. -The rekeying will be initiated when the SA's remaining lifetime is -less than the rekeymargin plus a random percentage, between 0 and -rekeyfuzz, of the rekeymargin. -.LP -Similarly, when an SA that was initiated by the peer has only a bit of -lifetime left, \fBpluto\fP will try to initiate the creation of a -replacement. -To give preference to the initiator, this rekeying will only be initiated -when the SA's remaining lifetime is half of rekeymargin. -If rekeying is done by the responder, the roles will be reversed: the -responder for the old SA will be the initiator for the replacement. -The former initiator might also initiate rekeying, so there may -be redundant SAs created. -To avoid these complications, make sure that rekeymargin is generous. -.LP -One risk of having the former responder initiate is that perhaps -none of its proposals is acceptable to the former initiator -(they have not been used in a successful negotiation). -To reduce the chances of this happening, and to prevent loss of security, -the policy settings are taken from the old SA (this is the case even if -the former initiator is initiating). -These may be stricter than those of the connection. -.LP -\fBpluto\fP will not rekey an SA if that SA is not the most recent of its -type (IPsec or ISAKMP) for its potential connection. -This avoids creating redundant SAs. -.LP -The random component in the rekeying time (rekeyfuzz) is intended to -make certain pathological patterns of rekeying unstable. If both -sides decide to rekey at the same time, twice as many SAs as necessary -are created. This could become a stable pattern without the -randomness. -.LP -Another more important case occurs when a security gateway has SAs -with many other security gateways. Each of these connections might -need to be rekeyed at the same time. This would cause a high peek -requirement for resources (network bandwidth, CPU time, entropy for -random numbers). The rekeyfuzz can be used to stagger the rekeying -times. -.LP -Once a new set of SAs has been negotiated, \fBpluto\fP will never send -traffic on a superseded one. Traffic will be accepted on an old SA -until it expires. -.SS Selecting a Connection When Responding: Road Warrior Support -.LP -When \fBpluto\fP receives an initial Main Mode message, it needs to -decide which connection this message is for. It picks based solely on -the source and destination IP addresses of the message. There might -be several connections with suitable IP addresses, in which case one -of them is arbitrarily chosen. (The ISAKMP SA proposal contained in -the message could be taken into account, but it is not.) -.LP -The ISAKMP SA is negotiated before the parties pass further -identifying information, so all ISAKMP SA characteristics specified in -the connection description should be the same for every connection -with the same two host IP addresses. At the moment, the only -characteristic that might differ is authentication method. -.LP -Up to this point, -all configuring has presumed that the IP addresses -are known to all parties ahead of time. This will not work -when either end is mobile (or assigned a dynamic IP address for other -reasons). We call this situation ``Road Warrior''. It is fairly tricky -and has some important limitations, most of which are features of -the IKE protocol. -.LP -Only the initiator may be mobile: -the initiator may have an IP number unknown to the responder. When -the responder doesn't recognize the IP address on the first Main Mode -packet, it looks for a connection with itself as one end and \fB%any\fP -as the other. -If it cannot find one, it refuses to negotiate. If it -does find one, it creates a temporary connection that is a duplicate -except with the \fB%any\fP replaced by the source IP address from the -packet; if there was no identity specified for the peer, the new IP -address will be used. -.LP -When \fBpluto\fP is using one of these temporary connections and -needs to find the preshared secret or RSA private key in \fIipsec.secrets\fP, -and and the connection specified no identity for the peer, \fB%any\fP -is used as its identity. After all, the real IP address was apparently -unknown to the configuration, so it is unreasonable to require that -it be used in this table. -.LP -Part way into the Phase 1 (Main Mode) negotiation using one of these -temporary connection descriptions, \fBpluto\fP will be receive an -Identity Payload. At this point, \fBpluto\fP checks for a more -appropriate connection, one with an identity for the peer that matches -the payload but which would use the same keys so-far used for -authentication. If it finds one, it will switch to using this better -connection (or a temporary derived from this, if it has \fB%any\fP -for the peer's IP address). It may even turn out that no connection -matches the newly discovered identity, including the current connection; -if so, \fBpluto\fP terminates negotiation. -.LP -Unfortunately, if preshared secret authentication is being used, the -Identity Payload is encrypted using this secret, so the secret must be -selected by the responder without knowing this payload. This -limits there to being at most one preshared secret for all Road Warrior -systems connecting to a host. RSA Signature authentications does not -require that the responder know how to select the initiator's public key -until after the initiator's Identity Payload is decoded (using the -responder's private key, so that must be preselected). -.LP -When \fBpluto\fP is responding to a Quick Mode negotiation via one of these -temporary connection descriptions, it may well find that the subnets -specified by the initiator don't match those in the temporary -connection description. If so, it will look for a connection with -matching subnets, its own host address, a peer address of \fB%any\fP -and matching identities. -If it finds one, a new temporary connection is derived from this one -and used for the Quick Mode negotiation of IPsec SAs. If it does not -find one, \fBpluto\fP terminates negotiation. -.LP -Be sure to specify an appropriate nexthop for the responder -to send a message to the initiator: \fBpluto\fP has no way of guessing -it (if forwarding isn't required, use an explicit \fB%direct\fP as the nexthop -and the IP address of the initiator will be filled in; the obsolete -notation \fB0.0.0.0\fP is still accepted). -.LP -\fBpluto\fP has no special provision for the initiator side. The current -(possibly dynamic) IP address and nexthop must be used in defining -connections. These must be -properly configured each time the initiator's IP address changes. -\fBpluto\fP has no mechanism to do this automatically. -.LP -Although we call this Road Warrior Support, it could also be used to -support encrypted connections with anonymous initiators. The -responder's organization could announce the preshared secret that would be used -with unrecognized initiators and let anyone connect. Of course the initiator's -identity would not be authenticated. -.LP -If any Road Warrior connections are supported, \fBpluto\fP cannot -reject an exchange initiated by an unknown host until it has -determined that the secret is not shared or the signature is invalid. -This must await the -third Main Mode message from the initiator. If no Road Warrior -connection is supported, the first message from an unknown source -would be rejected. This has implications for ease of debugging -configurations and for denial of service attacks. -.LP -Although a Road Warrior connection must be initiated by the mobile -side, the other side can and will rekey using the temporary connection -it has created. If the Road Warrior wishes to be able to disconnect, -it is probably wise to set \fB\-\-keyingtries\fP to 1 in the -connection on the non-mobile side to prevent it trying to rekey the -connection. Unfortunately, there is no mechanism to unroute the -connection automatically. -.SS Debugging -.LP -\fBpluto\fP accepts several optional arguments, useful mostly for debugging. -Except for \fB\-\-interface\fP, each should appear at most once. -.TP -\fB\-\-interface\fP \fIinterfacename\fP -specifies that the named real public network interface should be considered. -The interface name specified should not be \fBipsec\fP\fIN\fP. -If the option doesn't appear, all interfaces are considered. -To specify several interfaces, use the option once for each. -One use of this option is to specify which interface should be used -when two or more share the same IP address. -.TP -\fB\-\-ikeport\fP \fIport-number\fP -changes the UDP port that \fBpluto\fP will use -(default, specified by IANA: 500) -.TP -\fB\-\-ctlbase\fP \fIpath\fP -basename for control files. -\fIpath\fP.ctl is the socket through which \fBwhack\fP communicates with -\fBpluto\fP. -\fIpath\fP.pid is the lockfile to prevent multiple \fBpluto\fP instances. -The default is \fI/var/run/pluto\fP). -.TP -\fB\-\-secretsfile\fP \fIfile\fP -specifies the file for authentication secrets -(default: \fI/etc/ipsec.secrets\fP). -This name is subject to ``globbing'' as in \fIsh\fP(1), -so every file with a matching name is processed. -Quoting is generally needed to prevent the shell from doing the globbing. -.TP -\fB\-\-adns\fP \fIpathname\fP -.TP -\fB\-\-lwdnsq\fP \fIpathname\fP -specifies where to find \fBpluto\fP's helper program for asynchronous DNS lookup. -\fBpluto\fP can be built to use one of two helper programs: \fB_pluto_adns\fP -or \fBlwdnsq\fP. You must use the program for which it was built. -By default, \fBpluto\fP will look for the program in -\fB$IPSEC_DIR\fP (if that environment variable is defined) or, failing that, -in the same directory as \fBpluto\fP. -.TP -\fB\-\-nofork\fP -disable ``daemon fork'' (default is to fork). In addition, after the -lock file and control socket are created, print the line ``Pluto -initialized'' to standard out. -.TP -\fB\-\-uniqueids\fP -if this option has been selected, whenever a new ISAKMP SA is -established, any connection with the same Peer ID but a different -Peer IP address is unoriented (causing all its SAs to be deleted). -This helps clean up dangling SAs when a connection is lost and -then regained at another IP address. -.TP -\fB\-\-stderrlog\fP -log goes to standard out {default is to use \fIsyslogd\fP(8)) -.LP -\fBpluto\fP is willing to produce a prodigious amount of debugging -information. To do so, it must be compiled with \-DDEBUG. There are -several classes of debugging output, and \fBpluto\fP may be directed to -produce a selection of them. All lines of -debugging output are prefixed with ``|\ '' to distinguish them from error -messages. -.LP -When \fBpluto\fP is invoked, it may be given arguments to specify -which classes to output. The current options are: -.TP -\fB\-\-debug-raw\fP -show the raw bytes of messages -.TP -\fB\-\-debug-crypt\fP -show the encryption and decryption of messages -.TP -\fB\-\-debug-parsing\fP -show the structure of input messages -.TP -\fB\-\-debug-emitting\fP -show the structure of output messages -.TP -\fB\-\-debug-control\fP -show \fBpluto\fP's decision making -.TP -\fB\-\-debug-lifecycle\fP -[this option is temporary] log more detail of lifecycle of SAs -.TP -\fB\-\-debug-kernel\fP -show \fBpluto\fP's interaction with the kernel -.TP -\fB\-\-debug-dns\fP -show \fBpluto\fP's interaction with \fBDNS\fP for KEY and TXT records -.TP -\fB\-\-debug-oppo\fP -show why \fBpluto\fP didn't find a suitable DNS TXT record to authorize opportunistic initiation -.TP -\fB\-\-debug-all\fP -all of the above -.TP -\fB\-\-debug-private\fP -allow debugging output with private keys. -.TP -\fB\-\-debug-none\fP -none of the above -.LP -The debug form of the -\fBwhack\fP command will change the selection in a running -\fBpluto\fP. -If a connection name is specified, the flags are added whenever -\fBpluto\fP has identified that it is dealing with that connection. -Unfortunately, this is often part way into the operation being observed. -.LP -For example, to start a \fBpluto\fP with a display of the structure of input -and output: -.IP -pluto \-\-debug-emitting \-\-debug-parsing -.LP -To later change this \fBpluto\fP to only display raw bytes: -.IP -whack \-\-debug-raw -.LP -For testing, SSH's IKE test page is quite useful: -.IP -\fIhttp://isakmp-test.ssh.fi/\fP -.LP -Hint: ISAKMP SAs are often kept alive by IKEs even after the IPsec SA -is established. This allows future IPsec SA's to be negotiated -directly. If one of the IKEs is restarted, the other may try to use -the ISAKMP SA but the new IKE won't know about it. This can lead to -much confusion. \fBpluto\fP is not yet smart enough to get out of such a -mess. -.SS Pluto's Behaviour When Things Go Wrong -.LP -When \fBpluto\fP doesn't understand or accept a message, it just -ignores the message. It is not yet capable of communicating the -problem to the other IKE daemon (in the future it might use -Notifications to accomplish this in many cases). It does log a diagnostic. -.LP -When \fBpluto\fP gets no response from a message, it resends the same -message (a message will be sent at most three times). This is -appropriate: UDP is unreliable. -.LP -When pluto gets a message that it has already seen, there are many -cases when it notices and discards it. This too is appropriate for UDP. -.LP -Combine these three rules, and you can explain many apparently -mysterious behaviours. In a \fBpluto\fP log, retrying isn't usually the -interesting event. The critical thing is either earlier (\fBpluto\fP -got a message which it didn't like and so ignored, so it was still -awaiting an acceptable message and got impatient) or on the other -system (\fBpluto\fP didn't send a reply because it wasn't happy with -the previous message). -.SS Notes -.LP -Each IPsec SA is assigned an SPI, a 32-bit number used to refer to the SA. -The IKE protocol lets the destination of the SA choose the SPI. -The range 0 to 0xFF is reserved for IANA. -\fBPluto\fP also avoids choosing an SPI in the range 0x100 to 0xFFF, -leaving these SPIs free for manual keying. -Remember that the peer, if not \fBpluto\fP, may well chose -SPIs in this range. -.SS Policies -.LP -This catalogue of policies may be of use when trying to configure -\fBPluto\fP and another IKE implementation to interoperate. -.LP -In Phase 1, only Main Mode is supported. We are not sure that -Aggressive Mode is secure. For one thing, it does not support -identity protection. It may allow more severe Denial Of Service -attacks. -.LP -No Informational Exchanges are supported. These are optional and -since their delivery is not assured, they must not matter. -It is the case that some IKE implementations won't interoperate -without Informational Exchanges, but we feel they are broken. -.LP -No Informational Payloads are supported. These are optional, but -useful. It is of concern that these payloads are not authenticated in -Phase 1, nor in those Phase 2 messages authenticated with HASH(3). -.IP \(bu \w'\(bu\ 'u -Diffie Hellman Groups MODP 1024 and MODP 1536 (2 and 5) -are supported. -Group MODP768 (1) is not supported because it is too weak. -.IP \(bu -Host authetication can be done by RSA Signatures or Pre-Shared -Secrets. -.IP \(bu -3DES CBC (Cypher Block Chaining mode) is the only encryption -supported, both for ISAKMP SAs and IPSEC SAs. -.IP \(bu -MD5 and SHA1 hashing are supported for packet authentication in both -kinds of SAs. -.IP \(bu -The ESP, AH, or AH plus ESP are supported. If, and only if, AH and -ESP are combined, the ESP need not have its own authentication -component. The selection is controlled by the \-\-encrypt and -\-\-authenticate flags. -.IP \(bu -Each of these may be combined with IPCOMP Deflate compression, -but only if the potential connection specifies compression and only -if the kernel is configured with IPCOMP support. -.IP \(bu -The IPSEC SAs may be tunnel or transport mode, where appropriate. -The \-\-tunnel flag controls this when \fBpluto\fP is initiating. -.IP \(bu -When responding to an ISAKMP SA proposal, the maximum acceptable -lifetime is eight hours. The default is one hour. There is no -minimum. The \-\-ikelifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -When responding to an IPSEC SA proposal, the maximum acceptable -lifetime is one day. The default is eight hours. There is no -minimum. The \-\-ipseclifetime flag controls this when \fBpluto\fP -is initiating. -.IP \(bu -PFS is acceptable, and will be proposed if the \-\-pfs flag was -specified. The DH group proposed will be the same as negotiated for -Phase 1. -.SH SIGNALS -.LP -\fBPluto\fP responds to \fBSIGHUP\fP by issuing a suggestion that ``\fBwhack\fP -\-\-listen'' might have been intended. -.LP -\fBPluto\fP exits when it receives \fBSIGTERM\fP. -.SH EXIT STATUS -.LP -\fBpluto\fP normally forks a daemon process, so the exit status is -normally a very preliminary result. -.TP -0 -means that all is OK so far. -.TP -1 -means that something was wrong. -.TP -10 -means that the lock file already exists. -.LP -If \fBwhack\fP detects a problem, it will return an exit status of 1. -If it received progress messages from \fBpluto\fP, it returns as status -the value of the numeric prefix from the last such message -that was not a message sent to syslog or a comment -(but the prefix for success is treated as 0). -Otherwise, the exit status is 0. -.SH FILES -\fI/var/run/pluto.pid\fP -.br -\fI/var/run/pluto.ctl\fP -.br -\fI/etc/ipsec.secrets\fP -.br -\fI$IPSEC_LIBDIR/_pluto_adns\fP -.br -\fI$IPSEC_EXECDIR/lwdnsq\fP -.br -\fI/dev/urandom\fP -.SH ENVIRONMENT -\fIIPSEC_LIBDIR\fP -.br -\fIIPSEC_EXECDIR\fP -.br -\fIIPSECmyid\fP -.SH SEE ALSO -.LP -The rest of the FreeS/WAN distribution, in particular \fIipsec\fP(8). -.LP -\fIipsec_auto\fP(8) is designed to make using \fBpluto\fP more pleasant. -Use it! -.LP -.IR ipsec.secrets (5) -describes the format of the secrets file. -.LP -\fIipsec_atoaddr\fP(3), part of the FreeS/WAN distribution, describes the -forms that IP addresses may take. -\fIipsec_atosubnet\fP(3), part of the FreeS/WAN distribution, describes the -forms that subnet specifications. -.LP -For more information on IPsec, the mailing list, and the relevant -documents, see: -.IP -.nh -\fIhttp://www.ietf.cnri.reston.va.us/html.charters/ipsec-charter.html\fP -.hy -.LP -At the time of writing, the most relevant IETF RFCs are: -.IP -RFC2409 The Internet Key Exchange (IKE) -.IP -RFC2408 Internet Security Association and Key Management Protocol (ISAKMP) -.IP -RFC2407 The Internet IP Security Domain of Interpretation for ISAKMP -.LP -The FreeS/WAN web site -and the mailing lists described there. -.SH HISTORY -This code is released under the GPL terms. -See the accompanying file COPYING-2.0 for more details. -The GPL does NOT apply to those pieces of code written by others -which are included in this distribution, except as noted by the -individual authors. -.LP -This software was originally written -for the FreeS/WAN project - -by Angelos D. Keromytis -(angelos@dsl.cis.upenn.edu), in May/June 1997, in Athens, Greece. -Thanks go to John Ioannidis for his help. -.LP -It is currently (2000) -being developed and maintained by D. Hugh Redelmeier -(hugh@mimosa.com), in Canada. The regulations of Greece and Canada -allow us to make the code freely redistributable. -.LP -Kai Martius (admin@imib.med.tu-dresden.de) contributed the initial -version of the code supporting PFS. -.LP -Richard Guy Briggs and Peter Onion - added the PFKEY2 support. -.LP -We gratefully acknowledge that we use parts of Eric Young's \fIlibdes\fP -package; see \fI../libdes/COPYRIGHT\fP. -.SH BUGS -.BR pluto -is a work-in-progress. It currently has many limitations. -For example, it ignores notification messages that it receives, and -it generates only Delete Notifications and those only for IPSEC SAs. -.LP -\fBpluto\fP does not support the Commit Flag. -The Commit Flag is a bad feature of the IKE protocol. -It isn't protected -- neither encrypted nor authenticated. -A man in the middle could turn it on, leading to DoS. -We just ignore it, with a warning. -This should let us interoperate with -implementations that insist on it, with minor damage. -.LP -\fBpluto\fP does not check that the SA returned by the Responder -is actually one that was proposed. It only checks that the SA is -acceptable. The difference is not large, but can show up in attributes -such as SA lifetime. -.LP -There is no good way for a connection to be automatically terminated. -This is a problem for Road Warrior and Opportunistic connections. -The \fB\-\-dontrekey\fP option does prevent the SAs from -being rekeyed on expiry. -Additionally, if a Road Warrior connection has a client subnet with a fixed IP -address, a negotiation with that subnet will cause any other -connection instantiations with that same subnet to be unoriented -(deleted, in effect). -See also the \-\-uniqueids option for an extension of this. -.LP -When \fBpluto\fP sends a message to a peer that has disappeared, -\fBpluto\fP receives incomplete information from the kernel, so it -logs the unsatisfactory message ``some IKE message we sent has been -rejected with ECONNREFUSED (kernel supplied no details)''. John -Denker suggests that this command is useful for tracking down the -source of these problems: -.br - tcpdump \-i eth0 icmp[0] != 8 and icmp[0] != 0 -.br -Substitute your public interface for eth0 if it is different. -.LP -The word ``authenticate'' is used for two different features. We must -authenticate each IKE peer to the other. This is an important task of -Phase 1. Each packet must be authenticated, both in IKE and in IPsec, -and the method for IPsec is negotiated as an AH SA or part of an ESP SA. -Unfortunately, the protocol has no mechanism for authenticating the Phase 2 -identities. -.LP -Bugs should be reported to the mailing list. -Caution: we cannot accept -actual code from US residents, or even US citizens living outside the -US, because that would bring FreeS/WAN under US export law. Some -other countries cause similar problems. In general, we would prefer -that you send detailed problem reports rather than code: we want -FreeS/WAN to be unquestionably freely exportable, which means being -very careful about where the code comes from, and for a small bug fix, -that is often more time-consuming than just reinventing the fix -ourselves. diff --git a/src/pluto/pluto.c b/src/pluto/pluto.c deleted file mode 100644 index 66fdb30b9..000000000 --- a/src/pluto/pluto.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "pluto.h" - -#include - -typedef struct private_pluto_t private_pluto_t; - -/** - * Private additions to pluto_t. - */ -struct private_pluto_t { - - /** - * Public members of pluto_t. - */ - pluto_t public; -}; - -/** - * Single instance of pluto_t. - */ -pluto_t *pluto; - -/** - * Described in header. - */ -void pluto_deinit() -{ - private_pluto_t *this = (private_pluto_t*)pluto; - this->public.events->destroy(this->public.events); - this->public.xauth->destroy(this->public.xauth); - free(this); - pluto = NULL; -} - -/** - * Described in header. - */ -bool pluto_init(char *file) -{ - private_pluto_t *this; - - INIT(this, - .public = { - .events = event_queue_create(), - .xauth = xauth_manager_create(), - }, - ); - pluto = &this->public; - - if (lib->integrity && - !lib->integrity->check_file(lib->integrity, "pluto", file)) - { - DBG1(DBG_LIB, "integrity check of pluto failed"); - return FALSE; - } - return TRUE; -} - diff --git a/src/pluto/pluto.h b/src/pluto/pluto.h deleted file mode 100644 index 2440093ca..000000000 --- a/src/pluto/pluto.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2010 Andreas Steffen - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup pluto pluto - * - * @defgroup xauth xauth - * @ingroup pluto - * - * @defgroup pplugins plugins - * @ingroup pluto - * - * @addtogroup pluto - * @{ - */ - -#ifndef PLUTO_H_ -#define PLUTO_H_ - -typedef struct pluto_t pluto_t; - -#include -#include - -#include - -/** - * Pluto daemon support object. - */ -struct pluto_t { - - /** - * event queue (callbacks, executed by the pluto main thread) - */ - event_queue_t *events; - - /** - * manager for payload attributes - */ - xauth_manager_t *xauth; - -}; - -/** - * The single instance of pluto_t. - * - * Set between calls to pluto_init() and pluto_deinit() calls. - */ -extern pluto_t *pluto; - -/** - * Initialize pluto. - * - * @return FALSE if integrity check failed - */ -bool pluto_init(char *file); - -/** - * Deinitialize pluto. - */ -void pluto_deinit(void); - -#endif /** PLUTO_H_ @}*/ - diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c deleted file mode 100644 index dbc857ce2..000000000 --- a/src/pluto/plutomain.c +++ /dev/null @@ -1,852 +0,0 @@ -/* Pluto main program - * Copyright (C) 1997 Angelos D. Keromytis. - * Copyright (C) 1998-2001 D. Hugh Redelmeier. - * Copyright (C) 2009 Andreas Steffen - Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* missing from on old systems */ -#include -#include -#include -#include -#include - -#ifdef CAPABILITIES -#ifdef HAVE_SYS_CAPABILITY_H -#include -#endif /* HAVE_SYS_CAPABILITY_H */ -#endif /* CAPABILITIES */ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "constants.h" -#include "defs.h" -#include "myid.h" -#include "ca.h" -#include "certs.h" -#include "ac.h" -#include "connections.h" -#include "foodgroups.h" -#include "packet.h" -#include "demux.h" /* needs packet.h */ -#include "server.h" -#include "kernel.h" -#include "log.h" -#include "keys.h" -#include "adns.h" /* needs */ -#include "dnskey.h" /* needs keys.h and adns.h */ -#include "state.h" -#include "ipsec_doi.h" /* needs demux.h and state.h */ -#include "ocsp.h" -#include "crl.h" -#include "fetch.h" -#include "crypto.h" -#include "nat_traversal.h" -#include "virtual.h" -#include "timer.h" -#include "vendor.h" -#include "builder.h" -#include "whack_attribute.h" -#include "pluto.h" - -#ifdef ANDROID -#include /* for AID_VPN */ -#endif - -/** - * Number of threads in the thread pool, if not specified in config. - */ -#define DEFAULT_THREADS 4 - -/** - * PID file, in which pluto stores its process id - */ -static char pluto_lock[sizeof(ctl_addr.sun_path)] = DEFAULT_CTLBASE LOCK_SUFFIX; - -/** - * TRUE if the lock has been checked. This helps to avoid any unintended - * deletion of the lock or control socket. - */ -static bool pluto_lock_checked = FALSE; - -/** - * Global reference to PID file (required to truncate, if undeletable) - */ -static FILE *pidfile = NULL; - - -static void usage(const char *mess) -{ - if (mess != NULL && *mess != '\0') - fprintf(stderr, "%s\n", mess); - fprintf(stderr - , "Usage: pluto" - " [--help]" - " [--version]" - " [--optionsfrom ]" - " \\\n\t" - "[--nofork]" - " [--stderrlog]" - " [--nocrsend]" - " \\\n\t" - "[--strictcrlpolicy]" - " [--crlcheckinterval ]" - " [--cachecrls]" - " [--uniqueids]" - " \\\n\t" - "[--interface ]" - " [--ikeport ]" - " \\\n\t" - "[--ctlbase ]" - " \\\n\t" - "[--perpeerlogbase ] [--perpeerlog]" - " \\\n\t" - "[--secretsfile ]" - " [--policygroupsdir ]" - " \\\n\t" - "[--adns ]" - "[--pkcs11module ]" - "[--pkcs11keepstate]" - "[--pkcs11initargs ]" -#ifdef DEBUG - " \\\n\t" - "[--debug-none]" - " [--debug-all]" - " \\\n\t" - "[--debug-raw]" - " [--debug-crypt]" - " [--debug-parsing]" - " [--debug-emitting]" - " \\\n\t" - "[--debug-control]" - " [--debug-lifecycle]" - " [--debug-kernel]" - " [--debug-dns]" - " \\\n\t" - "[--debug-oppo]" - " [--debug-controlmore]" - " [--debug-private]" - " [--debug-natt]" -#endif - " \\\n\t" - "[--nat_traversal] [--keep_alive ]" - " \\\n\t" - "[--force_keepalive] [--disable_port_floating]" - " \\\n\t" - "[--virtual_private ]" - "\n" - "strongSwan "VERSION"\n"); - exit_pluto(mess == NULL? 0 : 1); -} - -static bool check_lock() -{ - struct stat stb; - FILE *fpid; - - if (stat(pluto_lock, &stb) == 0) - { - fpid = fopen(pluto_lock, "r"); - if (fpid) - { - char buf[64]; - pid_t pid = 0; - - memset(buf, 0, sizeof(buf)); - if (fread(buf, 1, sizeof(buf), fpid)) - { - buf[sizeof(buf) - 1] = '\0'; - pid = atoi(buf); - } - fclose(fpid); - if (pid && kill(pid, 0) == 0) - { /* such a process is running */ - return TRUE; - } - } - fprintf(stderr, "pluto: removing lock file \"%s\", process not " - "running\n", pluto_lock); - unlink(pluto_lock); - } - pluto_lock_checked = TRUE; - return FALSE; -} - -static void fill_lock(void) -{ - pidfile = fopen(pluto_lock, "w"); - if (pidfile) - { - fprintf(pidfile, "%u\n", (u_int)getpid()); - fflush(pidfile); - } - /* keep pidfile open so we can truncate it, if we cannot delete it */ -} - -static void delete_lock(void) -{ - /* because unlinking the PID file may fail, we truncate it to ensure the - * daemon can be properly restarted. one probable cause for this is the - * combination of not running as root and the effective user lacking - * permissions on the parent dir(s) of the PID file */ - if (pluto_lock_checked) - { - if (pidfile) - { - ignore_result(ftruncate(fileno(pidfile), 0)); - fclose(pidfile); - } - unlink(pluto_lock); - /* delete this here to avoid that exit_pluto calls delete the socket */ - delete_ctl_socket(); - } -} - - -/* by default pluto sends certificate requests to its peers */ -bool no_cr_send = FALSE; - -/* by default the CRL policy is lenient */ -bool strict_crl_policy = FALSE; - -/* by default CRLs are cached locally as files */ -bool cache_crls = FALSE; - -/* by default pluto does not check crls dynamically */ -long crl_check_interval = 0; - -/* path to the PKCS#11 module */ -char *pkcs11_module_path = NULL; - -/* by default pluto logs out after every smartcard use */ -bool pkcs11_keep_state = FALSE; - -/* by default pluto does not allow pkcs11 proxy access via whack */ -bool pkcs11_proxy = FALSE; - -/* argument string to pass to PKCS#11 module. - * Not used for compliant modules, just for NSS softoken - */ -static const char *pkcs11_init_args = NULL; - -/* options read by optionsfrom */ -options_t *options; - -int main(int argc, char **argv) -{ - bool fork_desired = TRUE; - bool log_to_stderr_desired = FALSE; - bool nat_traversal = FALSE; - bool nat_t_spf = TRUE; /* support port floating */ - unsigned int keep_alive = 0; - bool force_keepalive = FALSE; - char *virtual_private = NULL; -#ifdef CAPABILITIES - int keep[] = { - CAP_NET_ADMIN, - CAP_NET_BIND_SERVICE, -#ifdef ANDROID - CAP_NET_RAW, -#endif - }; -#endif /* CAPABILITIES */ - - /* initialize library and optionsfrom */ - if (!library_init(NULL)) - { - library_deinit(); - exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); - } - if (!libhydra_init("pluto")) - { - libhydra_deinit(); - library_deinit(); - exit(SS_RC_INITIALIZATION_FAILED); - } - if (!pluto_init(argv[0])) - { - pluto_deinit(); - libhydra_deinit(); - library_deinit(); - exit(SS_RC_DAEMON_INTEGRITY); - } - options = options_create(); - - /* handle arguments */ - for (;;) - { -# define DBG_OFFSET 256 - static const struct option long_opts[] = { - /* name, has_arg, flag, val */ - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { "optionsfrom", required_argument, NULL, '+' }, - { "nofork", no_argument, NULL, 'd' }, - { "stderrlog", no_argument, NULL, 'e' }, - { "nocrsend", no_argument, NULL, 'c' }, - { "strictcrlpolicy", no_argument, NULL, 'r' }, - { "crlcheckinterval", required_argument, NULL, 'x'}, - { "cachecrls", no_argument, NULL, 'C' }, - { "uniqueids", no_argument, NULL, 'u' }, - { "interface", required_argument, NULL, 'i' }, - { "ikeport", required_argument, NULL, 'p' }, - { "ctlbase", required_argument, NULL, 'b' }, - { "secretsfile", required_argument, NULL, 's' }, - { "foodgroupsdir", required_argument, NULL, 'f' }, - { "perpeerlogbase", required_argument, NULL, 'P' }, - { "perpeerlog", no_argument, NULL, 'l' }, - { "policygroupsdir", required_argument, NULL, 'f' }, - { "adns", required_argument, NULL, 'a' }, - { "pkcs11module", required_argument, NULL, 'm' }, - { "pkcs11keepstate", no_argument, NULL, 'k' }, - { "pkcs11initargs", required_argument, NULL, 'z' }, - { "pkcs11proxy", no_argument, NULL, 'y' }, - { "nat_traversal", no_argument, NULL, '1' }, - { "keep_alive", required_argument, NULL, '2' }, - { "force_keepalive", no_argument, NULL, '3' }, - { "disable_port_floating", no_argument, NULL, '4' }, - { "debug-natt", no_argument, NULL, '5' }, - { "virtual_private", required_argument, NULL, '6' }, -#ifdef DEBUG - { "debug-none", no_argument, NULL, 'N' }, - { "debug-all", no_argument, NULL, 'A' }, - { "debug-raw", no_argument, NULL, DBG_RAW + DBG_OFFSET }, - { "debug-crypt", no_argument, NULL, DBG_CRYPT + DBG_OFFSET }, - { "debug-parsing", no_argument, NULL, DBG_PARSING + DBG_OFFSET }, - { "debug-emitting", no_argument, NULL, DBG_EMITTING + DBG_OFFSET }, - { "debug-control", no_argument, NULL, DBG_CONTROL + DBG_OFFSET }, - { "debug-lifecycle", no_argument, NULL, DBG_LIFECYCLE + DBG_OFFSET }, - { "debug-klips", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-kernel", no_argument, NULL, DBG_KERNEL + DBG_OFFSET }, - { "debug-dns", no_argument, NULL, DBG_DNS + DBG_OFFSET }, - { "debug-oppo", no_argument, NULL, DBG_OPPO + DBG_OFFSET }, - { "debug-controlmore", no_argument, NULL, DBG_CONTROLMORE + DBG_OFFSET }, - { "debug-private", no_argument, NULL, DBG_PRIVATE + DBG_OFFSET }, - - { "impair-delay-adns-key-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_KEY_ANSWER + DBG_OFFSET }, - { "impair-delay-adns-txt-answer", no_argument, NULL, IMPAIR_DELAY_ADNS_TXT_ANSWER + DBG_OFFSET }, - { "impair-bust-mi2", no_argument, NULL, IMPAIR_BUST_MI2 + DBG_OFFSET }, - { "impair-bust-mr2", no_argument, NULL, IMPAIR_BUST_MR2 + DBG_OFFSET }, -#endif - { 0,0,0,0 } - }; - /* Note: we don't like the way short options get parsed - * by getopt_long, so we simply pass an empty string as - * the list. It could be "hvdenp:l:s:" "NARXPECK". - */ - int c = getopt_long(argc, argv, "", long_opts, NULL); - - /* Note: "breaking" from case terminates loop */ - switch (c) - { - case EOF: /* end of flags */ - break; - - case 0: /* long option already handled */ - continue; - - case ':': /* diagnostic already printed by getopt_long */ - case '?': /* diagnostic already printed by getopt_long */ - usage(""); - break; /* not actually reached */ - - case 'h': /* --help */ - usage(NULL); - break; /* not actually reached */ - - case 'v': /* --version */ - { - const char **sp = ipsec_copyright_notice(); - - printf("strongSwan "VERSION"%s\n", compile_time_interop_options); - for (; *sp != NULL; sp++) - puts(*sp); - } - exit_pluto(0); - break; /* not actually reached */ - - case '+': /* --optionsfrom */ - if (!options->from(options, optarg, &argc, &argv, optind)) - { - exit_pluto(1); - } - continue; - - case 'd': /* --nofork*/ - fork_desired = FALSE; - continue; - - case 'e': /* --stderrlog */ - log_to_stderr_desired = TRUE; - continue; - - case 'c': /* --nocrsend */ - no_cr_send = TRUE; - continue; - - case 'r': /* --strictcrlpolicy */ - strict_crl_policy = TRUE; - continue; - - case 'x': /* --crlcheckinterval