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/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 ++ 522 files changed, 49738 insertions(+), 25680 deletions(-) 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 (limited to 'src/libcharon') 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_ @}*/ -- cgit v1.2.3